views:

5079

answers:

4

I have a .xib file containing a UIView and 2 UILabel subviews linked to a class named Note with outlets assigned to each label appropriately, the definition for this class contains the following.

@interface Note : UIView {
    IBOutlet UILabel *time;
    IBOutlet UILabel *content;
}

I'm constructing this with the following code

NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"Note" owner:self options:nil];
note = [nibViews lastObject];
[self addSubview:note];

Now, in my Note class dealloc phase, I'm not releasing either time or content, but I'm wondering if I should?

- (void)dealloc {
    [super dealloc];
}

I'm assuming I don't because I'm not explicitly retaining these objects anywhere in my code, and I don't synthesize these into getter/setters. But I don't know enough about nib unarchiving to know whether I should be releasing these in my dealloc phase or not?

+2  A: 

I belive you are correct. See the documentation links below for more details.

Documentation:

bjartek
+1  A: 

This is correct for the iPhone; it would not be correct on the Mac, though.

However, you may want to rework this code. It isn't safe to assume that the view will be the last object loaded from the nib. I'd suggest instead that you either connect it to a "note" outlet in your view controller or scan the list for an object that's a subclass of Note. (If you're loading multiple Notes and you use the outlet option, just make sure you add one Note before loading another.)

Brent Royal-Gordon
What do you mean I can't guarantee it will be the last object? Do you mean because its possible to order the top level of a nib in any order you want, or that at the time of unarchiving the order can be changed from what appears in interface builder?
seanalltogether
The order when unarchiving is not guaranteed. For example, between iPhone OS 2.1 and 2.2 a single UITableViewCell placed in a xib when loaded was returned in different positions within the array (even with only a single object there is more than one element in the array returned by loadNibNamed).
Kendall Helmstetter Gelner
A: 

You DO need to release it. See

"As it rebuilds the object hierarchy, however, UIKit reestablishes connections between the objects using the setValue:forKey: method, which uses the available setter method or retains the object by default if no setter method is available." in Nib Object Retention

In other words, because you haven't specified these entries as @property (which implicitly declares a setter), or provided a setter directly, there is no available setter method, and the final part of this paragraph applies - the object is retained by default.

You should, in your dealloc() method, set all IBOutlets to nil using

self.outletName = nil;

If no setter is defined, then setValue will autorelease the old value (make sure you have an NSAutoreleasePool if running in a thread). If a setter is defined, it will perform whatever behaviour you defined. Either way, the set to nil will do exactly the right thing, and ensure you get no memory leaks. Do NOT do this

outletName = nil;

This will directly set the member variable, and bypass calling setValue.

See the documentation of NSObject setValue:forKey for more details.

Running the Performance Tool (Leaks) will not show a leak, but you can verify that there is actually a leak by looking at the current running total of allocated memory.

cf The Airsource - Memory Management and NIBs

Airsource Ltd
self.outletName = nil;No, do *not* do this; you should not use accessor methods in dealloc.
mmalc
Re "In other words, because you haven't specified these entries as @property": declaring a property has nothing to do with it. It's the presence or absence of the accessors themselves that's important, not the syntactic sugar.
mmalc
Agreed, and edited. My point was that he hadn't declared accessors even by the hidden method of doing it as an @property, but that didn't come across to well.
Airsource Ltd
Regarding accessor methods, you made this point on my blog as well, and I still disagree.
Airsource Ltd
+2  A: 

You should release an IBOutlet even if you're not writing or synthesizing accessor methods. The NIB lifecycle documentation says that although unarchived objects are initially set to autorelease, the retain count on them is bumped up by an extra 1 when UIKit hooks up all the IBOutlet connection bindings. You therefore need to manually decrement via release when you're done.

It's not obvious that UIKit would be doing this so you might assume you can just leave the setter/getter methods off and trust that everything is autoreleased. But that's not the case.

Notice that Interface Builder templates explicitly release any IBOutlets, so any you add should be treated likewise.

DX Griffiths