Be careful with weak references

I’m working on an update to VideoBuffet. One of the changes is that movies are loaded on a background thread, to make the main UI responsive during loading. So I’ve a block of code in one of my view controllers that looks like this:

- (void) setCurrentPathURLs:(NSArray*)URLs
{
    [self moviesStartedLoading];

    __weak id weakSelf = self;
    [self.moviesDoc setMovieURLs:URLs completion:^{
        [weakSelf moviesFinishedLoading];
    }];
}

The little dance with a __weak reference is to avoid a retain cycle. The controller has a strong reference to moviesDoc, moviesDoc has a strong reference to the block, and because the block references self, it will have a strong reference to it. By making a weak reference to self, it won’t be retained by the block, and the cycle is broken.

I thought this was all good, until I did some sanity testing on 10.7 Lion, and discovered that it simply crashed when trying to open a movie. It didn’t take long to trace it back to the above code. Then I remembered this. Whoops, I’m making a weak reference to an NSViewController. Turns out that’s fine in 10.8, but not 10.7, according to the Transitioning to ARC Release Notes:

Note: In addition, in OS X v10.7, you cannot create weak references to
instances of NSFontManager, NSFontPanel, NSImage, NSTableCellView,
NSViewController, NSWindow, and NSWindowController. In addition, in
OS X v10.7 no classes in the AV Foundation framework support weak references.

The solution is to simply make it __unsafe_unretained, as in:

- (void) setCurrentPathURLs:(NSArray*)URLs
{
    [self moviesStartedLoading];

    __unsafe_unretained id weakSelf = self;
    [self.moviesDoc setMovieURLs:URLs completion:^{
        [weakSelf moviesFinishedLoading];
    }];
}

Really, though, the moral of the story is: test your app, on all OS’es it supports. If we hadn’t gone back and tested with 10.7, we’d never have discovered this, and we’d have ended up with many 1 star reviews.