Search code examples
iphoneiosuiviewcontrollernsnotificationcenterdealloc

View controller dealloc not called when using NSNotificationCenter code block method with ARC


When I use -addObserverForName: object: queue: usingBlock: for NSNotificationCenter in the -viewDidLoad: method of my view controller, the -dealloc method ends up not being called.

(When I remove -addObserverForName: object: queue: usingBlock:, -dealloc is called again.)

Using -addObserver: selector: name: object: doesn't seem to have this problem. What am I doing wrong? (My project is using ARC.)

Below is an example of my implementation, in case I'm doing something wrong here:

[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
                                                  object:nil
                                                   queue:nil
                                              usingBlock:^(NSNotification *note) {
                                                  updateResult = YES;
                                              }];

Thanks in advance for any help.

I've tried adding the following (to no avail):

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    if ([self isMovingFromParentViewController]) {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
}

Solution

  • updateResult is an instance variable which prevents the object from being deallocated as it is retained by that block.

    In other words, you got a retain cycle. The object retains the block and the block retains the object.

    You will need to create a weak or unsafe_unretained reference to that instance and its variable for loosing that relationship.

    Add the following prior to your notification block:

    __unsafe_unretained YouObjectClass *weakSelf = self;
    

    or (in case you are on iOS5 and above)

    __weak YouObjectClass *weakSelf = self;
    

    Then, within that block, reference the object via that new weak reference:

    [[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
                                                      object:nil
                                                       queue:nil
                                                  usingBlock:^(NSNotification *note) {
                                                      weakSelf.updateResult = YES;
                                                  }];
    

    Please note that retain-cycles are not a bad thing per se. Sometimes you actually want them to happen. But those are instances where you are certain that the cycle will be broken after a specific time (e.g. Animation Blocks). The cycle is broken once the block has executed and is removed from the stack.