Tuesday, December 2, 2008

Outlets - Property vs. Instance Variable

When we were writing our iPhone programming book, all of Apple's sample code and documentation used the IBOutlet keyword exactly how we had always used it in Cocoa for Mac OS X, placed in front of the instance variable declaration, like so
#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController {
IBOutlet UILabel *myLabel;

}
@property (nonatomic, retain) UILabel *myLabel;
@end

Somewhere along the line, I'm not exactly sure when, they started putting the IBOutlet modifier in the property declaration instead, like so:
#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController {
UILabel *myLabel;

}
@property (nonatomic, retain) IBOutlet UILabel *myLabel;
@end

Now, in practice, there's absolutely no difference in the way a controller class functions based on where you place the IBOutlet keyword. I've used both approaches, even mingled within the same class, and have noticed no difference. That wasn't enough for me, though; I wanted to know if there was any underlying difference between the two - any difference in how the connections were made.

You see, early on, about the time of SDK2, I recall somebody saying that they had tested it and the mutators for their IBOutlets weren't getting called when the outlet connections were made. This came as a surprise because the sample source code was using properties for all IBOutlets, even though that wasn't the way it had been done in Cocoa on the Mac, and if the mutators weren't getting used, there wouldn't be any reason to declare a property for the outlets.

This made me wonder if, perhaps, Interface Builder only used the mutator if you put the IBOutlet keyword on the property declaration line but not if you put it preceding the instance variable declaration. There seemed to be a logic to that, given Apple's change in the preferred placement of the IBOutlet keyword from the instance variable to the property. If that's the case, then it would be important to know, because you could get slight differences in behavior in some rare circumstances based on which you used.

Wondering should lead to exploration, so I decided to find out. It's easy enough to test - I created an iPhone application project with two labels on a view, and two outlets to be connected to those two labels. One of the outlets was given the IBOutlet keyword preceding the instance variable declaration, the other was given the IBOutlet declaration as part of the property. In both cases, I implemented the mutator methods manually so that they would print a statement to the log whenever they were called in addition to doing the assignment.

And the Result?

It appears that where you place the IBOutlet keyword, on all current versions of the SDK (2.0, 2.1, 2.2), is purely stylistic and has no impact on what's happening under the hood. For both outlets, the mutator was called when the outlets were connected during application startup.

So, it seems that you can use whichever keyword placement you prefer, although Apple definitely seems to be going with placing the IBOutlet in the property declaration for all their new sample code and documentation code listings, so unless you feel strongly that it should be on the instance variable, that's probably the best place to put it, and probably where we'll put it if we ever publish a second edition.

No comments:

Post a Comment