Is it necessory to define property for an IBOutlet field?
I have seen many iPhone examples to use IBOutlet as a field linked to a UI control in Interface Builder, and the field is also defined as property in the interface class. For example, the following codes are similar ones from Apple example codes:
// in .h file
@interface MyViewController : UIViewController {
IBOutlet UILabel* _firstName;
IBOutlet UILabel* _lastName;
...
}
@property (nonatomic, retain) UILabel* firstName;
@property (nonatomic, retain) UILabel* lastName;
...
@end
// in .m file
@implementation MyViewController {
@synthetic firstName = _firstName;
@synthetic lastName = _lastName;
...
@end
I tried to link labels in Interface Builder to my controller class IBOutlets and I can see _firstName and _lastName. Since the linkage is directly from Interface Builder to my interface class members (开发者_运维知识库even private ones if I place @private directive). Do I need to define properties for those fields?
Actually, I tried to remove these properties and it seems my codes work fine. By defining properties, my class expose them as public. I don't have any usage or reason for them as properties within or out side my codes. My question is that if this practice, defining fields as properties, necessary? Do I miss any thing such as memory management which might be called from Objective-C concept or framework?
As Jeremie Wekdin mentioned that, my question is somehow duplicated. The similar question and answers do reveal that in case of nib/xib file being used, there is memory issue to be considered.
In short, Cocoa will look for setOutletName first, and use the property method to set UI control object; otherwise, Cocoa will direct set to the class member variable and retain it. That means the filed object should be released in dealloc method.
That's fine. However, in case of my question, my field variable has different name from its corresponding property name, like _firstName and firstName. In this case, I think that Cocoa is not smart enough to figure out the property method and object retrieved from nib/xib is directly set to the class member.
To verify it, I overwrite the setter:
// in .m file
@implementation MyViewController {
@synthetic firstName = _firstName;
- (void) setFirstName:(UILabel*) value {
NSLog("_firstname: %@", _firstName);
[_firstname autorelease];
_firstName = [value retain];
}
Then I load my view, the log message does not show in the XCode's output console. However, if I keep the variable name and property name the same. I do see the setter is called:
// in .h
@interface MyViewController : UIViewController {
IBOutlet UILabel* firstName;
...
}
@property (nonatomic, retain) UILabel* firstName;
...
@end
// in .m file
@implementation MyViewController {
@synthetic firstName;
- (void) setFirstName:(UILabel*) value {
NSLog("firstName: %@", firstName);
[firstName autorelease];
firstName = [value retain];
}
...
@end
In the output console, when the view shows, I see:
firstName: (null)
As the duplicated QA suggested, I read the Appl's Resource Programming Guide. Find the document in the section The Nib Object Life Cycle, The Object Loading Process, and #3 Outlet connection. You should see that Mac OS X and iPhone OS have different ways to connect outlet to objects. "In iPhone OS, the nib-loading code uses the setValue:forKey: method to reconnect each outlet"
So I tried the following codes:
@implementation MyViewController {
@synthetic firstName = _firstName;
- (void) setValue:(id) value forKey:(NSString*) key {
NSLog("forKey: %@; value: %@", key, value);
if ([key isEqualToString:@"_firstName"])
// It should then call the accessor or property
// self._firstName = value;
// to set value, like the follow codes in the setter:
[_firstName autorelease];
_firstName = [value retain];
}
...
}
...
@end
I recompiled my code again and I did see all the property setter calls, including the key _firstName. Continued from Apple's doc:
"That method (setValue:forKey:) similarly looks for an appropriate accessor method and falls back on other means when that fails."
This explains why in my case(property name is different from outlet variable name) the property is called by Cocoa.
In conclusion, there is a memory issue when IBOutlet and nib/xib are used (as a way to load views) for a field control. It would be nice to let Cocoa to find out a defined accessor or property to set a field variable, which handles retaining objects. If you define a property for an IBOutlet field variable, both should have the same. As a result, the codes will work in both Mac OS X and iPhone OS.
精彩评论