views:

3189

answers:

3

In most examples I see the following setup of IBOutlets:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *fooLabel;

@end

FooController.m:

@implementation FooController

@synthesize fooLabel;

@end

But this works also fine (notice: no property and no synthesize):



(Example B)

FooController.h:

@interface FooController : UIViewController {
    IBOutlet UILabel *fooLabel;
}

@end

FooController.m:

@implementation FooController

@end

Are there any downsides of defining IBOutlets as in Example B? Like memory leaks? Seems to work fine and I prefer to not expose the IBOutlets as public properties as they are not used as such, they are only used in the controller implementation. Defining it in three places without a real need does not strike me as very DRY (Don't Repeat Yourself).

A: 

The end result is exactly the same, but you have to keep a few things in mind:

  • When using instance fields as outlets, you should NOT release them in dealloc.

  • When using properties that have the (retain) attribute, you have to release the property in dealloc (using self.property=nil or by releasing the backing variable). This makes it a lot more transparent as to what's going on.

Actually it all comes down to the same old rule: "thou shalt release what you alloc/retain". So in case you use an instance field as outlet, you didn't alloc/retain it, so you shouldn't release it.

Philippe Leybaert
This advice is correct for Mac OS X, but not iPhone OS. See my answer below.
Jon Hess
Calling "self.property=nil" in a dealloc method is not a good practice to get into. You should not call methods from init or dealloc, if you're subclassed your subclass probably isn't expecting those setters to get called durring after it's dealloced, or before it's initted.
Jon Hess
It's the only way to release auto-retaining properties that use instance variable synthesis (without any explicit declaration of backing fields). You don't have a choice, good practice or not.
Philippe Leybaert
Sure you have a choice, declare a backing instance variable if you're not using garbage collection.
Jon Hess
That's the whole point: there's no backing instance variable when you use instance variable synthesis. So if you choose to use automatic instance variable synthesis, the only way to release it is by setting the property to nil.
Philippe Leybaert
+16  A: 

On Mac OS X, IBOutlets are connected like this:

  1. Look for a method called set<OutletName>:. If it exists call it.
  2. If no method exists, look for an instance variable named <OutletName>, set it without retaining.

On iPhone OS, IBOutlets are connected like this:

  1. call [object setValue:outletValue forKey:@"<OutletName>"]

The behavior of set value for key is to do something like this:

  1. Look for a method called set<OutletName>:. If it exists call it.
  2. If no method exists, look for an instance variable named , set it and retain it.

If you use a property, you'll fall into the "Look for a method called set<OutletName>:..." case on both platforms. If you just use an instance variable, then you'll have different retain/release behavior on Mac OS X VS iPhone OS. There's nothing wrong with using an instance variable, you just need to deal with this difference in behavior as you switch between platforms.

Here's a link to full documentation on just this topic. http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6

Jon Hess
Hi Jon, Thank you for the detailed answer! Very helpful
WardB
what happens if the variable name is different from property name? Does it matter if different?
David.Chu.ca
The "OutletName" name above is defined as what ever is next to the "IBOutlet" keyword in source code.If IBOutlet is in the @property, it doesn't matter what the instance variable is named since a setter will be found. If for some reason a setter didn't exist, there would be an exception raised when connecting the outlet.If the IBOutlet keyword is on the instance variable, and a setter exists with a name that doesn't match, the setter won't get called.
Jon Hess
+3  A: 

On Mac OS X, IBOutlets are not retained by defaults. This is the opposite of the behavior on iPhone OS: on iPhone OS, if you don't declare a property it is retained and you must release this property in the dealloc method. Additionally, the 64-bit runtime can synthesize instance variables using property declarations. That means that someday the instance variables (with the IBOutlet) may be omitted.

For these reasons it is more homogeneous and compatible to create always a property and use the IBOutlet only in the property. Unfortunately, it is also more verbose.

In your first example you always have to release the outlet in the dealloc method. In your second example you must release the outlet only with iPhone OS.

Freeman