3
votes

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.

3

3 Answers

3
votes

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.

2
votes

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.

2
votes

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:

  1. Always use direct assignment to an ivar. Switch to setter methods only for ivars for which setter must perform some additional work beside assignment.
  2. 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.