LS_
LS_

Reputation: 7129

Cannot remove NSNotificationCenter

I use 2 NSNotificationCenter and in order to avoid retain cycles I've created a weakSelf like this: __unsafe_unretained AugmentedRealityViewController *weakSelf = self;

    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {


        if (weakSelf.architectWorldNavigation.wasInterrupted) {
            [weakSelf.architectView reloadArchitectWorld];
        }

        [weakSelf startWikitudeSDKRendering];
    }];
    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {

        [weakSelf stopWikitudeSDKRendering];
    }];

The problem is that even if I remove them inside the dealloc they keep getting fired and the app crashes.

Inside the dealloc in order to remove the NSNotificationCenter I use the following code:

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];

    [self.architectView removeFromSuperview];
}

It gets called when I leave the ViewController but the Notifications still works.. Can someone tell me what's wrong with the code and how to fix the problem?

Upvotes: 1

Views: 574

Answers (3)

Jody Hagins
Jody Hagins

Reputation: 28409

In general, you are better off preferring the selector method of handling notifications. There are certainly good reasons for using the block based API, but your case seems tailor made for the other way.

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(applicationDidBecomeActiveNotification:)
           name:UIApplicationDidBecomeActiveNotification
         object:nil];

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(applicationWillResignActiveNotification:)
           name:UIApplicationWillResignActiveNotification
         object:nil];

- (void)applicationDidBecomeActiveNotification:(NSNotification*)notification {
    if (self.architectWorldNavigation.wasInterrupted) {
        [self.architectView reloadArchitectWorld];
    }
    [self startWikitudeSDKRendering];
}

- (void)applicationWillResignActiveNotification:(NSNotification*)notification {
    [self stopWikitudeSDKRendering];
}

Then, you can simply remove yourself, since you are the actual observer.

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Upvotes: 3

ogres
ogres

Reputation: 3690

It is because you are not adding self to NSNotificationCenter, you are adding the block and then trying to remove self

When you are adding Block to NSNotificationCenter it actually returns the object which you can use later to remove this code from NotificationCenter

__unsafe_unretained AugmentedRealityViewController *weakSelf = self;

self.becomeActiveHandler = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if (weakSelf.architectWorldNavigation.wasInterrupted) {
        [weakSelf.architectView reloadArchitectWorld];
    }
    [weakSelf startWikitudeSDKRendering];
}];

self.willResignActiveHandler = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    [weakSelf stopWikitudeSDKRendering];
}];

and then in dealloc , you can remove these handlers

[[NSNotificationCenter defaultCenter] removeObserver:self.becomeActiveHandler];
[[NSNotificationCenter defaultCenter] removeObserver:self.willResignActiveHandler];

Upvotes: 1

Avi
Avi

Reputation: 7552

1) Remove the __unsafe_unretained attribute. It may not be hurting, but it's not doing anything useful.

2) You are not capturing the return value from [NSNotificationCenter addObserverForName:object:queue:usingBlock:], which means you have no way to unregister for the notifications. This method creates a proxy object that listens to the notification and runs the block. If you don't hold on to a reference and unregister at some point, you have a memory leak and a notification handler that you don't need.

Upvotes: 1

Related Questions