Correct way to alloc/init instance variables in Objective-C? - iphone

I was looking at some sample code on Jeff LaMarche's excellent blog when I came across the following:
- (void)applicationDidFinishLaunching:(UIApplication*)application
{
CGRect rect = [[UIScreen mainScreen] bounds];
window = [[UIWindow alloc] initWithFrame:rect];
GLViewController *theController = [[GLViewController alloc] init];
self.controller = theController;
[theController release];
// ...
}
In the .h, we see that "window" and "controller" are ivars declared as so:
#interface OpenGLTestAppDelegate : NSObject
{
UIWindow *window;
GLViewController *controller;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet GLViewController *controller;
#end
My question is: Why are "window" and "controller" assigned in different ways?
I think I understand why each kind of assignment works (keeping track of retain count), but why are they assigned in different ways? Specifically, why isn't controller assigned in the same way window is with a single line like so without going through the setter:
controller = [[GLViewController alloc] init];
In general, when would you use the single line method and when would you use the multiple line method?
Thanks.

Does he create a custom setter for the controller instance variable?
If so, there may be code which is called when the controller variable is changed through the setter. Merely setting the controller variable with:
controller = [[GLViewController alloc] init];
would not invoke the setter method; however, assigning the newly allocated object to a local variable then setting it with:
self.controller = theController;
would invoke the setter method since it is a shorthand way of writing:
[self setController:theController];
and the extra code in the setter would be executed. This is commonly where you would expect the differentiation between the two methods.
Edit:
Evidently, after taking a look at the code, he doesn't implement a custom setter method, however the method that he has used is still most commonly used when a custom setter method would be implemented.
My guess at the reason behind the extra code would be that he plans to release the variable after allocation, and if assigned to a local variable, he can call the setter method with the local variable and then call release on the local variable afterwards. This would be overall more readable than using
[[self controller] release]
However, it is an odd way to do it, as the synthesized implementation of the setter will retain the instance variable, yet he then releases it once it has been set to the instance variable, and as the release call cancels out the retain call, it would make more sense to set the variable using the one-line method.

The extra code seems to be just because he specifically wants to use the property (setter method). In his implementation (GLView.m), -setController also sets a boolean ivar based on whether the controller responds to (implements) the -setupView: method.
Even so, it would seem that a one-line solution would work just as well:
self.controller = [[[GLViewController alloc] init] autorelease];
The same line as an explicit message send (without dot syntax) works as well:
[self setController:[[[GLViewController alloc] init] autorelease]];
Either approach will leave the new controller with the proper retain count, and still uses the setter property as desired.
(Note: The code in question is linked at the end of this blog post.)
Edit:
Sorry for any confusion. The code has a "GLViewController *controller" ivar and property both in ___PROJECTNAMEASIDENTIFIER___AppDelegate.m and GLView.m, and I was looking at the latter. (In the former, the setter is indeed synthesized, and it will retain the controller. On lines 77-81, you can see the code I mentioned, and he doesn't actually retain the controller — only the AppDelegate retains it.)
In the app delegate code, the synthesized setter will retain the GLViewController, so my one-line replacement advice still stands. One can argue both ways about readability, but for those who understand the retain-release idiom well, I would suggest that the one-line version is much more readable. It communicates the intent succinctly, and even provides an implicit hint that the setter will retain the controller. The extra local variable is really just unnecessary fluff.

As Quinn pointed out, the assignment to the controller ivar may be written in one line using autorelease method. The reason to use more verbose version is exactly to avoid autorelease and use manual release instead. This is due to Apple recommendation to minimize the use of autorelease pools on iPhone. So you must store the reference to the newly allocated object in a local variable to release it after a call to setter.
Considering the question when to use direct assignment to an instance variable (as in the case of window ivar) and when to use a setter method (as in the case of controller ivar), it is mostly a question of style, but you better be consistent.
There are two styles of ivar setting:
Always use direct assignment to an ivar. Switch to setter methods only for ivars for which setter must perform some additional work beside assignment.
Always use setter methods for all ivars.
Personally, I think that use of the second style results in more consistent and maintainable code. If some day you realize that your setter must perform more work you should change only the setter, while when using the first style you also should change all occurrences of direct assignment to the setter call.
Just found the good discussion of the issue in another thread: instance variable/ method argument naming in Objective C.

Related

"Copy" when using ARC

I know that when using ARC and you have an NSString property, you do #property(nonatomic, copy) just as you would MRC. But I'm wondering, after I converted my project to ARC, I still have this in my initializer method:
_someString = [someStringParameter copy]
Is this a bug? Or even with ARC, do I still need to explicitly say "copy" ? Or should I just do:
self.someString = someStringParameter
and all will be OK? Bit confused here...
You'd never use self.someString = anything in your initialiser. The dot notation is a method call. You shouldn't call methods on classes that aren't fully instantiated yet. Most demonstrable failure case: a subclass overrides setSomeString: — where is it in its init when that method is called?
ARC will handle proper retains and releases on instance variables but can't automatically do copies — e.g. there are __strong and __weak modifiers but no __copy. So you still need explicitly to copy when doing a direct instance variable assignment.
_someString = [someStringParameter copy];
Is this a bug?
No.
Or even with ARC, do I still need to explicitly say "copy" ?
Absolutely.
You're assigning the instance variable by copy and it's perfectly legit under ARC. As opposed to that, doing just:
_someString = someStringParamenter;
will cause ARC to automatically retain (not copy) it, resulting in something like
_someString = [someStringParameter retain];
This happens because under ARC variables have an implicit __strong identifier unless specified otherwise.
self.someString = someStringParameter
This is right, and both under ARC and MRC you'll get the object to be copied if you provided the copy attribute in the property declaration.
That said, it's still a bad idea to use accessor methods in initializers, since they may have unwanted side effects in case you have a custom implementation for them. Check out this answer on the subject: Should I refer to self.property in the init method with ARC?

iphone - properties and instance variables

Suppose I have this code...
foo.h
#interface Foo : NSObject {
NSString *aString; // 1
}
#property (nonatomic, retain) NSString *aString;
foo.m
#synthesize aString = _aString;
....
- (void)dealloc {
[aString release];
[super dealloc];
}
My questions are:
do I really need to declare aString in "1"? (see code)
if I am synthesizing aString = _aString, I am already creating an instance
variable, right?
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc?
thanks.
You are mixing up the property and the backing variable. "aString" is the property, which you access via method call (e.g. [self aString]). "_aString" is the backing variable, which you access directly (e.g. _aString).
Taking your questions in order:
No. This is an unused variable because you told the compiler to use _aString as the variable. (You don't actually need to declare either one in the modern run-time.)
Yes, as indicated in my answer to the first question.
Because the compiler expects you to send a message to an object, and "aString" is undefined as written. Normally you would use [self aString] to access the object, but this is a special case: in -dealloc and in -initXYZ you don't use accessor methods because of potential side effects. Switch to [_aString release] and everything will work (unless you have ARC, in which case you don't release at all.
With your #synthesize, the instance variable (your "1") should be NSString* _aString.
The reason you use synthesize with a differently named variable is so that you always use self.aString to properly release the old object instead of accidentally overwriting the pointer by directly modifying aString.
Do you have ARC enabled? If so, that's why Xcode complains about releasing it.
To answer your questions in order:
No. There might some sort of "best-practice" reason that I'm missing, but #property will synthesize the instance variable as well.
When you declare aString = _aString, what that allows you to do is directly manipulate _aString without accessing the synthesized getter/setter (by calling _aString) or use the synthesized getter/setters (by calling self.aString).
You are likely releasing it somewhere else, someone else is over-releasing it, or you're using ARC. With NSStrings (and other simple objects that have deep copy method readily available), I find it best to use #property (copy), and _aString = [stringPassedToInit copy], so that you are the only one handling your string's retain count. If you're using ARC, you don't need to worry about retain/release in most instances.
No, you don't need to declare ivars any more (since iOS 3 I think). You can delete the entire { ... } part of your interface declaration and it won't make any difference.
It's complaining because your ivar is named _aString, not aString. You need to say
[_aString release]
instead.
Answers : -
do I really need to declare aString in "1"? (see code) - Now with iOS 4 onwards you won't need to declare.
if I am synthesizing aString = _aString, I am already creating an instance variable, right? - Yes
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc? - now you need to use this - self.aString = nil, this will take care.
My answers are:
NO
YES
Try [_string release] instead.

Assigning ivars using self keyword in an object's init method

I've read that it's bad to use self.ivar = (convenience method) in and object's 'init' method, as this messes with inheritance.
However, if you know you're not going to subclass your object, is it ok to use the self keyword assignment?
i.e. self.iVar = [Object objectConvenienceMethod];
The reason I ask is this. I create a new object with its own init method, and in that method, I perform various initial assignments. Since I don't use the self keyword, I assign them directly to the iVars, and therefore use the alloc methods rather than the convenience methods. I.e.
iVar = [[Object alloc] init];
Or if I use a convenience method, I retain it. I.e.
iVar = [[Object convenienceMethod]retain]
But... when I run my program with the memory leak tool on, all of these assignments are identified as memory leaks.
If I can use the self keyword plus a convenience method instead of alloc-init, then this would avoid the problem.
If I choose to use the alloc-init approach though, where am I supposed to release the iVars?? Just in dealloc?
Thanks for your help :)
Michael
No, because it isn't only subclass behavior you need to take into account — superclass implementations and even the behavior of code generated by the framework (e.g. synthesized accessors and the black magic used to implement KVO) can also cause trouble. It will probably be OK, but that's still a significant chance of being not-OK. All in all, it's best just to follow Apple's recommendation and assign directly.
Assigning to ivars in init shouldn't be reported as leaks in a properly functioning program. If you're seeing that, there's some other problem that you need to address. Try reducing the problem to a minimal case that we can try out and ask about that — then we can tell what's wrong.
If you alloc or retain them in your class's init method, you should release them in the corresponding dealloc method.
I am thinking your "enclosing" class is not being released, and hence its dealloc method is not being called resulting in your iVars not being released.

Would it be correct/ellegant use only alloc without init?

If we don't want to implement init method in our class, and bearing in mind that init in NSObject only returns an instance of the object without initialization, I don't see the point of calling init if we already get the instance with alloc. I have tried and it works, but I am not sure it won't cause future problems.
myClass *newObject = [myClass alloc];
instead of:
myClass *newObject = [[myClass alloc] init];
Thanks a lot.
No, just calling alloc would not be correct. alloc zeroes out all instance variables of the object, init then has the chance to set all or some instance variables to their default values. Some classes even use their init methods to create another instance and return that one instead of the one you allocated.
Many classes expect that their init methods get called and would possibly cause crashes if you don't call init. If you are talking about a custom class that inherits directly from NSObject and needs no initialization of instance variables, you might get away with [myClass alloc] but it is definitely not good programming style.
I think that it is not a good idea.
Read Cocoa Design Pattern, especially the "Two stage creation"
You can also read this article http://www.informit.com/articles/article.aspx?p=1398610
I think that it wouldn't matter much if you didn't implement a "- (id)init" because if you did, you would call NSObject's init method which just returns the same value you send to the method. Though it is a good idea to create your own init method to set your instance variable.
in runtime source code
perform -(id)init will call _objc_rootInit(self) and will return self. I guess only perform init is OK。

Using self in method call

When using property/synthesize for a UITableView, UIButton, etc should self be included in the method call on that variable? Using UITableView as an example is there a difference between [self.myTableView visibleCells] and [myTableView visibleCells]? Or say [self.myImage setImage:...] and [myImage setImage:...]?
I've seen Apple code that does use self (Bubble Level) and examples in the book Beginning iPhone Development that do not use self. I'd like to understand this better, especially since using self in my UIScrollView method calls has caused erratic/buggy scrolling behavior. Thanks.
Using self.myTableView is another way of saying [self myTableView] (it can also be [self setMyTableView:...]; if used in an assignation statement). In other words, you're executing a method.
Using myTableView accesses the instance variable directly.
Personally, I generally prefer using the former method, since it usually frees me from manually managing memory and gives me the benefit of KVO notifications. However, there is the miniscule overhead of the extra method call, which you may wish to avoid.
Which style you choose to use is up to you, and each way has its benefits and disadvantages.
The difference comes down to how you define the property. For example, say you have the following:
#interface MyObject : NSObject {
NSObject *memberVariable;
}
#property (nonatomic, retain) NSObject *memberVariable;
#end
#implementation MyObject
#synthesize memberVariable;
#end
Specifying (nonatomic, retain) actually tells #synthesize how to create the getter and setter methods. Specifying retain causes the setter method to call retain on objects I pass to it. So, self.memberVariable = someOtherObject is equivalent to memberVariable = [someOtherObject retain];
This is also why you should never do self.memberVariable = [[NSObject alloc] init]; if you've specified retain in the property definition. alloc initializes the retain count to 1, passing the object to the setter method increases the retain count to 2.
This comes down to whether or not your accessor methods have custom behavior, in which case you'd always want the accessors called even from within the class, and whether you want to make sure KVO notifications are generated. If you're using stock accessors (e.g., synthesized) and it won't affect anything to access the instance variable directly from within the class, you're saving yourself a method call.