Search code examples
automatic-ref-countingiboutletnsviewcontrollernsstoryboard

NSViewController not dealloc'd when outlets are bound


I have the following files:

Main.storyboard

This is the same as the default storyboard created when creating a new project with a few additions: There is a button in the view which is connected to the button outlet of the view controller (instance of ViewController) and the doTheThing: action on the view controller.

ViewController.m

#import "ViewController.h"

@interface ViewController ()
@property (weak) IBOutlet NSButton *button;
@property (weak) NSViewController *controller;
@end

@implementation ViewController

- (IBAction)doTheThing:(id)sender {
    if (self.controller) {
        NSLog(@"Removing %@", self.controller);
        [self.controller.view removeFromSuperview];
        [self.controller removeFromParentViewController];
    } else {
        self.controller = [[NSStoryboard storyboardWithName:@"Another" bundle:[NSBundle mainBundle]] instantiateInitialController];
        [self addChildViewController:self.controller];
        [self.view addSubview:self.controller.view];
        NSLog(@"Adding %@", self.controller);
    }
}

@end

Another.storyboard

A simple storyboard containing a single scene (view controller + view) that is set to the initial controller and is an instance of AnotherViewController. There is a label in the view that is not connected to any outlet.

AnotherViewController.m

#import "AnotherViewController.h"

@interface AnotherViewController ()
@property (weak) IBOutlet NSTextField *label;
@end

@implementation AnotherViewController

- (void)dealloc {
    NSLog(@"Deallocing AnotherViewController %@", self);
}

@end

When I run the app and click the button, it adds the view controller and view from Another.storyboard, and when I click the button again they are removed and the instance of AnotherViewController is deallocated.

However, if I connect the label in Another.storyboard to the label outlet on the AnotherViewController, the deallocation never occurs. Why is this and what can I do to fix it?

Edit: I do have a few workarounds, but they aren't very desirable and I would prefer to understand why the recommended way (storyboards and outlets) isn't working properly.

Undesirable workaround 1: Do the same thing but load the view controller and view from a XIB file. This works as expected, but ideally I would be able to do the same thing using storyboards.

Undesirable workaround 2: Bind all my outlets manually in code in the view controller's viewDidLoad method. This is just tedious and ugly as it requires iterating through all the view's subviews and comparing identifiers.


Solution

  • Apple have confirmed (via bug report) that this is a known issue and will be fixed in OS X 10.10.3.