16

I'm an experienced iOS dev and I have decided to try my hand at some AppKit development. There are a couple of adjustments that I am making API-wise, but otherwise am finding OS X development to be, shall we say, 'familiar'.

I've been building my AppKit UIs in Interface Builder and noticed that when I use the WYSIWYG editor to create properties in my code files, Apple is creating the following:

@property (assign) IBOutlet NSTableView *tableView;

I find this very curious because the default way of doing things in iOS would have led me to do this:

@property (nonatomic, retain) IBOutlet NSTableView *tableView;

I realize that in Mac development I don't have the same memory constraints that I do on mobile, where a view could get unloaded and there may be a need for strong references to UI elements.

In the AppKit case I can pretty well assume that my UI elements will always be there unless I fiddle with the view hierarchy and remove it from its parent view. It would seem prudent to have a strong reference at all times in order to guard against unintentionally accessing dangling pointers.

Why is Apple creating a weak reference here, instead of a strong one?

Am I setting myself up for some unintended consequence by using strong references (but properly releasing in dealloc)? Is there some pattern here that I am missing?

1 Answer 1

16

As File's Owner, you should own any and all top-level objects in the nib. You generally do not need to own any objects within those objects, because a parent object will own its child objects; for example, a window will own its views.

AppKit's nib loader implicitly retains all top-level objects on behalf of the File's Owner. (This made sense before @property, synthesized accessors, and ARC existed.) Thus, even if the relevant properties are weak or unsafe_unretained (the latter being a synonym for assign), the owner will in fact own the top-level objects. And if you go the other way and make those properties strong (a.k.a. retain), then the FO has two ownerships of each object: the implicit ownership, and the strong-property ownership.

Assuming you're using manual reference counting, you can release the implicit ownership in awakeFromNib, but that's just made work. As long as you're not going to replace any of those objects after the nib is loaded (e.g., swap out a table view for another table view), an unsafe_unretained property will work just fine without a superfluous retain or any made work.

unsafe_unretained is named that (and that name is preferred over assign for object properties) for a reason, though. Returning the window-and-its-views example, suppose you own a window and know about one of its views. The view's superview is probably its only owner, so, when you close the window (or the user closes it), the view will get released and consequently deallocated. If your property to the view is unsafe_unretained/assign, you still know about this now-dead object, and trying to send a message to the view may cause a crash or an exception.

You should switch to ARC and declare the property as weak. That way, no redundant ownership is created, and the property will automatically be set to nil when the view dies, preventing an over-release crash from ensuing.

(If you're not the File's Owner, none of that applies to you and you should probably declare your properties as you see fit. Either weak or strong may be a good choice, depending on how you see your ownership hierarchy and what kind of object you're referencing.)

On iOS, UIKit's authors took out the now-problematic implicit retain. You are expected to write your own ownerships; if you mean to own an object from a nib or storyboard, you write a strong property, and if you mean only to know about it, you write a weak or unsafe_unretained one, exactly as you'd expect.

TL;DR: Hysterical reasons.

5
  • 1
    I was afraid that was going to be the answer, but very well explained, nonetheless. Aug 30, 2012 at 4:25
  • So we'd still need a [tableView release] in dealloc? If so, when does that release get called when using ARC?
    – MrMage
    Aug 31, 2012 at 15:30
  • @MrMage: You ordinarily wouldn't own a table view, since you'd normally put it into a window or container view in the nib, not have it at the top level of the nib. You'd own the window or top-level view, and simply know about the table view. Anything you do own, you must release. Aug 31, 2012 at 19:54
  • @MrMage: Under ARC, that release message cannot exist: release messages are illegal (as are retain and autorelease). This is largely because ARC releases your strong references for you; if you were allowed to do it yourself, it'd be much harder for ARC to think around what you're up to. (This is also why it complains about performSelector:, and why @selector(release) is also illegal.) One consequence of no releases is that you seldom need to write dealloc—any implementation that would consist entirely of [x release] messages simply goes away, done for you by the compiler. Aug 31, 2012 at 19:58
  • 1
    @MrMage: As for countering the implicit retain (which ARC doesn't know about, and so won't balance out), the documentation I linked to in the answer suggests using CFRelease. It's totally cheating (going behind ARC's back), but the only way to deal with the nib loader's implicit retain under ARC. Aug 31, 2012 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.