I was just wondering where I should set the values of variables for use in all my methods.
For example, let's say in my .h I say:
#property NSString *name; and then synthesize it in the .m. Where do I assign it a value so in my functions, say -(NSString *)changeUsername:(NSString *) changes and -(void)deleteUsername, I can access that data?
main() is the first thing that gets called in a command line program. Wouldn't you do it there (or somewhere called from main())?
Since you're talking about properties, you must have a class that you're instantiating. That class's designated initializer (-init or similar) is the right place to set up your properties and/or instance variables.
The only reason that Cocoa Touch apps defer some initialization tags to -viewDidLoad is that view controllers don't load their views when they're initialized and some properties or ivars are related to the view(s) that will be loaded. Those things clearly can't be set up until the view is loaded (or created), so -viewDidLoad becomes the best place for setting up those sorts of things.
Well you COULD do so in an initializer for your class and indeed, this would be the approach in C++ or maybe Java. In objective-c, you usually use lazy instantiation, and the best place to do that is in the getter for that property.
If someone assigns a value to the property the setter is called and everything is fine.
If someone asks FOR the value and it has not been set yet (is nil) you can create the object and/or assign a default value in the getter.
// Override accessor for name
- (NSString*)name
{
if (!_name) {
_name = #"unknown";
}
return _name;
}
The accessor methods are the only place you should be accessing instance variables directly.
Related
I have a feed that loads a array of:
•Status objects
•PhotoStatus objects - a subclass of Status
When a user clicks on a status in the feed it takes them to ViewCommentsViewController which has the following property that MUST be set in order for the view controller to work:
#property (nonatomic,strong) Status *status;
If I pass/assign:
ViewCommentsViewController.status=photoStatus;
Can I reliably still preserve the subclass properties of the photoStatus some how? Maybe by doing something like photoStatus *revertedPhotoStatus=status; in my view controller, or what is the right way to do what im trying to do? I dont want to have multiple view controller classes, and I don't want to go the sloppy route of having both photoStatus & status properties in my ViewCommentsViewController, so how do I reliably allow the loading of multiple types of content that are all subclasses of Status?
Can I reliably still preserve the subclass properties of the photoStatus some how
Yes, this just happens automatically. It's called polymorphism: a thing is the thing it is, not the thing you happen to type it as. So if you assign an actual PhotoStatus object to a variable typed as a Status, it remains a PhotoStatus under the hood. This mechanism is absolutely crucial; without it, subclass instances would not be very useful!
Note, however, that in order to treat your Status-typed object as a PhotoStatus object, if that is what it really is under the hood, you will need to cast it down to a PhotoStatus object. And if you do this and this happens not to be a PhotoStatus object, you may be heading for a crash later when a PhotoStatus message is sent to an object that is not in fact a PhotoStatus.
In the best of all worlds, you wouldn't need to test what kind of class something is. Instead, the class receiving the object would declare a pointer to a base class that implemented all necessary methods.
The implementations would be different but, in this case, a ViewCommentsViewController could make consistent calls to any kind of Status and know that the methods existed.
Another way of structuring things to assure this would be by using a protocol. That would make your declaration something like #property (nonatomic,strong) id<StatusProvider> status;.
I've typed isKindOfClass far too often to present myself as any kind of purist, but it's nice to use a clean approach when possible.
If you intend to use methods that are defined in the Status class but not PhotoStatus, you need to check the class of the returned object. To do this, you would normally do something along these lines:
Status *status = viewCommentsViewController.status;
if ([[status class] isSubclassOfClass: [PhotoStatus class]])
{
PhotoStatus *photoStatus = (PhotoStatus *) status;
// Handle photoStatus.
}
else
{
// Handle the other case.
}
If you want to save a few lines at the call site, you could add accessors like this:
#implementation Status
- (PhotoStatus *) asPhotoStatus
{
return nil;
}
#end
#implementation PhotoStatus
- (PhotoStatus *) asPhotoStatus
{
return self;
}
#end
and then just call
[[viewCommentsViewController.status asPhotoStatus] doSomething];
Edit: Since Xcode 4.2, sending a message to nil should always return a zero value or cause the returned struct to be filled with zeros. (Unfortunately I couldn't find a specification, but this blog post contains a summary.)
Given a class structure such as...
#interface SuperClassView : NSView #end
#interface SubClassedView : SuperClassView #property int aProp; #end
How can one instantiate a SubClassedView from an instance of a SuperClassView?
Say a method returns an instance of the superclass SuperView....
SuperClassView *superInstance = [ViewFactory makeSuperClassView];
but I want to get an instance of the subclass SubClassedView? It is not possible to simply "cast" it...
SubClassedView *subClsInstance = (SubClassedView*)[ViewFactory makeSuperClassView];
and there is no built-in (or easily-imagined implementation of an) NSObject method like
self = [super initWithInstance:[superInstance copy]];`
Is the only way to either copy the superclass instance's desired properties to the newly instantiated subclass object, like...
SubClassedView *subClsInstance = SubClassedView.new;
for (NSString* someKey in #["frame",#"color",#"someOtherProperty])
[subClsInstance setValue:[superInstance valueForKey:someKey] forKey:someKey];
Or add (swizzle at runtime) the subclass' "additional property methods" (in this case setAProp: and aProp) to the superclass instance (and also cast it upwards)...
SubClassedView *subClsInstance = (SubClassedView*)[ViewFactory makeSuperClassView];
[subClsInstance addSwizzleMethod:#selector(setAProp:) viaSomeMagic:....];
[subClsInstance addSwizzleMethod:#selector(aProp) viaSomeMagic:....];
Hopefully this is an easy runtime trick that I simply don't know... not a sad sign that I am haplessly trying to trick ObjC into multiple-inheritance via some embarrassing anti-pattern. Either way, ideas?
EDIT: Pending #BryanChen posting his comment as an answer this is achieved easily via his suggested runtime function, or as a category on NSObject á la..
#implementation NSObject (SettingClass)
- (void)setClass:(Class)kls { if (kls) object_setClass(self, kls); } #end
What you are trying to do is pretty non-idiomatic... it feels like you are trying to do something like prototype based OOP. A couple of quick points:
Don't do the swizzle. You can't swizzle onto an instance, you swizzle onto the class definition, so if you do that you won't be adding the subclasses methods onto "an" instance of the superclass, you will be adding them onto all instances of the superclass.
Yes, if you want to do this you just need to copy the the properties you want from the super into the new instance of the subclass.
You can have a factory method in the superclass that returns a subclass, and encapsulate all the the copying in there (so, -[SuperClassView makeSubclassView] that returns SubClassedView *. That is actually relatively common, and is how many of the class clusters are implemented (though they return private subclasses that conform to the implementation of the superclass)
object_setClass is not the droid you're looking for.
Yes, it will change the class of the instance. However, it will not change the size of it. So if your SubClassView declares extra properties or instance variables that are not declared on SuperClassView, then your attempts to access them on this frankenstein instance will result in (at best) buffer overflows, (probably) corrupted data, and (at worst) your app crashing.
It sounds like you really just want to use self in your factory method:
+ (instancetype)makeView {
return [[self alloc] init];
}
Then if you call [SuperClassView makeView], you get back an instance of SuperClassView. If you call [SubClassView makeView], you get back an instance of SubClassView.
"But," you say, "how do I customize the properties of the view if it's a SubClassView?"
Just like you would with anything else: you override the method on SubClassView:
#implementation SubClassView
+ (instancetype)makeView {
SubClassView *v = [super makeView];
v.answer = 42;
return v;
}
#end
object_setClass may or may not be the "runtime trick" you are looking for. It does isa swizzle which change the class of an instance at runtime. However it does have many constrains such as that the new class cannot have extra ivars. You can check this question for more details.
I think the better way to do is that instead of making view using [ViewFactory makeSuperClassView], make it [[SuperClassView alloc] initWithSomething]. Then you can do [[SubClassView alloc] initWithSomething]
or if you really want use ViewFactory, then make it [ViewFactory makeViewOfClass:]
In Apple's The Objective-C Programming Language p. 18, they make a distinction between setting a variable with self versus instance reference. e.g
myInstance.value =10;
self.value =10;
1. Would these two set different properties named value?
2. How could self work if there are several instances with properties named value?
They also assert, "If you do not use self., you access the instance variable directly." This would mean that the accessor would not be called if you use
myInstance.value =10;
and KVO wouldn't work. Is this true?
3. Using #Property and #Synthesize (with garbage collection), what is the proper way to set properties of different instances? And what good is the self reference?
A numeric example would help me, please.
1 - Would these two set different properties named value?
No, I think you misunderstand what the guide is saying when it makes a distinction between self.value and myInstance.value. In both cases the setter function (i.e., setValue:) is called.
You use self to access your own properties (that is, referencing properties from within functions in a class that you wrote). Like:
#interface MyObject : NSObject
#property( nonatomic ) NSInteger value;
- (void) doSomething;
#end
#implementation MyObject
#synthesize value;
- (void) doSomething
{
self.value = 10;
}
#end
Whereas you'd use myInstance to set a property in some other variable, from outside that class.
MyObject* anObject = [[MyObject alloc] init];
anObject.value = 10;
2 - How could self work if there are several instances with properties named value?
It wouldn't. See above.
They also assert, "If you do not use self., you access the instance variable directly." This would mean that the accessor would not be called if you use myInstance.value =10; and KVO wouldn't work. Is this true?
No. self.value and myInstance.value both call their accessors (setValue: in this case), and KVO will work. What that assertion means is that if you access an ivar from within your own class, not using the accessor, KVO will not work.
#interface MyObject : NSObject
#property( nonatomic ) NSInteger value;
- (void) doSomething;
#end
#implementation MyObject
#synthesize value;
- (void) doSomething
{
self.value = 10; // This invokes the accessor, and KVO works.
value = 10; // This just sets the instance variable, and KVO won't work.
}
#end
Using #Property and #Synthesize (with garbage collection), what is the proper way to set properties of different instances? And what good is the self reference? A numeric example would help me, please.
Just as shown above, use the instance name. self is only used for accessing properties within a class. Examples above.
The best way to under stand self is to think of how it is implemented, as a hidden argument with every method call so the method -[UIView drawRect:] has a c function implementation like
BOOL drawRect:( UIView * self, SEL _cmd, NSRect r ) { }; // of cause : is not legal in c
and calling the method is a little like (ignoring the dynamic look up)
UIView * v = ...
NSRect r = ...
drawRect:( v, #selector(drawRect:), r );
so if you invoke a property in the drawRect: implementation you are doing it for the hidden object parameter called self.
Accessing the instance variable directly will stop KVO from working, but sometimes you want that, for example when initialising them perhaps.
IF you mean automatic reference counting when you say Garbage Collection, most of the time for objects you want them to be strong or copy, immutable strings using copy will be turned into a retain and if it is mutable then you often want a copy to protect against the original being changed underneath you.
One potential issue with strong is that you can end up with circular references where if you follow the links around you comeback to the original object so each object is indirectly retaining itself and you have a catch-22 situation where the object has to release itself before it can release itself. So in these situations you need to use weak. You can usually workout who should retain and who should weak by think about which object conceptually owns the other.
For non-object you have to use assign.
self.property and [self method]; are strictly used within a class to refer to itself. You do not ever refer to the object within itself with anything but self.
On the contrary, use instances of an object to refer to an object from another class. For instance, I would refer to a UIImageView from my viewController in a way like:
UIImageView* imgView = [[UIImageView alloc] init];
[imgView setFrame:CGRectMake(0,0,320,480)];
But if I were editing a subclass of UIImageView that I called, say rotatingImageView:
#implementation rotatingImageView
-(id)init
{
//Super instantiation code that I don't remember at the moment goes here
[self setFrame:CGRectMake(0,0,320,480)];
}
This is just an example of a method.
Once again, you use self strictly within its own class, and you use other variables to reference an instance of another class.
Hope that makes sense.
My big problem was how an ivar and a property could be tied together when they have different names, especially with multiple ivars.
I finally found that if name of property doesn't match name of ivar, a new ivar is synthesized. This is accessed by self.propertyname (within object) or object.propertyname (outside of object), not the declared ivar.
To tie disparate names of ivar and property, equate them as in
#synthesize propertyname = ivarname.
Thanks to
http://blog.ablepear.com/2010/05/objective-c-tuesdays-synthesizing.html
Quick question... Well I understand that all properties start out as nil in Objective-C and that sending a message to nil does nothing, therefore you must initialize using [[Class alloc] init]; before sending a message to a newly created property. However, what about if I'm not sending messages to this property or if I set the property using self.property = something? Do I need to alloc init in these cases as well? Also, do UI properties start out as nil as well, such as a UILabel property that you drag out from your storyboard? Do these need alloc init?
Thanks to all who answer
Stunner did a good job of explaining not needing to alloc init objects that have already been created.
But if it is an object that doesn't exist, where are you going to create it? A very common pattern, which I mention because you mentioned it in your post, is lazy instantiation.
So you want an NSMutableArray property. You could alloc init it in some method before you use it, but then you have to worry about "does that method get called before I need my array?" or "am I going to call it again accidentally and re-initialize it."
So a failsafe place to do it is in the property's getter. It gets called every time you access the property.
.h
#property (nonatomic, strong) NSMutableArray* myArray;
.m
#synthesize myArray = _myArray;
- (NSMutableArray*)myArray
{
if (!_myArray) {
_myArray = [[NSMutableArray alloc] initWithCapacity:2];
}
return _myArray;
}
Every time you access that property, it says, "Does myArray exist? If not, create it. If it does, just return what I have."
Plus an added benefit with this design pattern is you aren't creating resources until you need them, versus creating them all at once, say, when your view controller loads or your app launches, which, depending on the requirements, could take a couple seconds.
The reality is when you do self.myProperty = [[Class alloc] init], you're not initializing your property. Rather, you're initializing an object that you tell your property (which is in fact a pointer) to point to. So if you already have an object that's allocated and initialized, you don't have to alloc/init again and you can do self.myProperty = object;
UI Properties do no start as nil, this is because when you add elements in the interface builder, the view owns the elements that you add and these objects are initialized automatically for you. This means if you're creating IBOutlets and connecting them to some properties, you don't have to alloc/init.
I hope this was helpful.
I don't have experience with Storyboards but I know that when you create objects via a xib file all objects are properly instantiated when you tell a view controller to use a xib file. So you need not worry about alloc/initing those objects in code.
Regarding using self.property = <something>, it depends on what something is. If something is any sort of existing object you need not do the alloc init on that object as the self.property = ... syntax calls the property's setter method which will retain, copy, assign, etc. the new value to the property appropriately.
Now any sort of existing object can be an alloc/init'ed object, or an autoreleased object obtained from a convenience method (NSString's stringWithFormat: for example).
As Kaan Dedeoglu pointed out, the self.property = ... syntax points (and retains) the ivar to the object in memory, and it is up to you to initialize that object if it isn't already instantiated.
No you do not need to [[Class alloc]init the properties in your init method.
However, I would encourage you to explicitly set them to Nil in your init method for clarity.
I have a category on NSObject which supposed to so some stuff. When I call it on an object, I would like to override its dealloc method to do some cleanups.
I wanted to do it using method swizzling, but could not figure out how. The only examples I've found are on how to replace the method implementation for the entire class (in my case, it would override dealloc for ALL NSObjects - which I don't want to).
I want to override the dealloc method of specific instances of NSObject.
#interface NSObject(MyCategory)
-(void)test;
#end
#implementation NSObject(MyCategory)
-(void)newDealloc
{
// do some cleanup here
[self dealloc]; // call actual dealloc method
}
-(void)test
{
IMP orig=[self methodForSelector:#selector(dealloc)];
IMP repl=[self methodForSelector:#selector(newDealloc)];
if (...) // 'test' might be called several times, this replacement should happen only on the first call
{
method_exchangeImplementations(..., ...);
}
}
#end
You can't really do this since objects don't have their own method tables. Only classes have method tables and if you change those it will affect every object of that class. There is a straightforward way around this though: Changing the class of your object at runtime to a dynamically created subclass. This technique, also called isa-swizzling, is used by Apple to implement automatic KVO.
This is a powerful method and it has its uses. But for your case there is an easier method using associated objects. Basically you use objc_setAssociatedObject to associate another object to your first object which does the cleanup in its dealloc. You can find more details in this blog post on Cocoa is my Girlfriend.
Method selection is based on the class of an object instance, so method swizzling affects all instances of the same class - as you discovered.
But you can change the class of an instance, but you must be careful! Here is the outline, assume you have a class:
#instance MyPlainObject : NSObject
- (void) doSomething;
#end
Now if for just some of the instances of MyPlainObject you'd like to alter the behaviour of doSomething you first define a subclass:
#instance MyFancyObject: MyPlainObject
- (void) doSomething;
#end
Now you can clearly make instances of MyFancyObject, but what we need to do is take a pre-existing instance of MyPlainObject and make it into a MyFancyObject so we get the new behaviour. For that we can swizzle the class, add the following to MyFancyObject:
static Class myPlainObjectClass;
static Class myFancyObjectClass;
+ (void)initialize
{
myPlainObjectClass = objc_getClass("MyPlainObject");
myFancyObjectClass = objc_getClass("MyFancyObject");
}
+ (void)changeKind:(MyPlainObject *)control fancy:(BOOL)fancy
{
object_setClass(control, fancy ? myFancyObjectClass : myPlainObjectClass);
}
Now for any original instance of MyPlainClass you can switch to behave as a MyFancyClass, and vice-versa:
MyPlainClass *mpc = [MyPlainClass new];
...
// masquerade as MyFancyClass
[MyFancyClass changeKind:mpc fancy:YES]
... // mpc behaves as a MyFancyClass
// revert to true nature
[MyFancyClass changeKind:mpc: fancy:NO];
(Some) of the caveats:
You can only do this if the subclass overrides or adds methods, and adds static (class) variables.
You also need a sub-class for ever class you wish to change the behaviour of, you can't have a single class which can change the behaviour of many different classes.
I made a swizzling API that also features instance specific swizzling. I think this is exactly what you're looking for: https://github.com/JonasGessner/JGMethodSwizzler
It works by creating a dynamic subclass for the specific instance that you're swizzling at runtime.