Luuk D. Jansen
Luuk D. Jansen

Reputation: 4508

NotificationCenter observers prevent dealloc with ARC

I am trying to debug a project which I have recently converted to use ARC. I am having a hard time determining why objects are not released and stay in memory (is there an easy way to see what reference keeps an object in memory?)

One problem seems with notification centre links. On viewDidLoad I register three notifications:

[notificationCenter addObserverForName: kAudioPlaybackStart
                                object: nil
                                 queue:[NSOperationQueue mainQueue]
                            usingBlock:^(NSNotification *note) {
                                [self handle_PlaybackStateStart:nil];
                            }];
[notificationCenter addObserverForName: kAudioPlaybackStop
                                object: nil
                                 queue:[NSOperationQueue mainQueue]
                            usingBlock:^(NSNotification *note) {
                                [self handle_PlaybackStateStop:nil];
                            }];
[notificationCenter addObserverForName: kAudioPlaybackPause
                                object: nil
                                 queue:[NSOperationQueue mainQueue]
                            usingBlock:^(NSNotification *note) {
                                [self handle_PlaybackStatePause:nil];
                            }];

Then, when the viewController is done I call a function unLoad:

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

    _mediaPlayerHelper = nil;
    _article = nil;
    _tableView = nil;
}

The reason I have a separate function is that viewDidUnload is not called unless all objects are released, so I need something to release them. Currently I call them on viewDidDisappear.

However, the code works fine (and view unloads) when commenting out the observers, but with the observers it doesn't seem to work and the view stays in memory. Any suggestions?

Upvotes: 2

Views: 1399

Answers (2)

eDeniska
eDeniska

Reputation: 101

You're not removing your observers when calling

[[NSNotificationCenter defaultCenter] removeObserver:self];

You have to pass not self, but return values of addObserverForName:... methods.

Something like this. For all of the observers.

@property (strong, nonatomic) id audioStartObserver;

-(void)viewDidLoad
{
    [super viewDidLoad];
    self.audioStartObserver = [notificationCenter addObserverForName: kAudioPlaybackStart
                            object: nil
                             queue:[NSOperationQueue mainQueue]
                        usingBlock:^(NSNotification *note) {
                            [self handle_PlaybackStateStart:nil];
                        }];
     // ...
 }

- (void) unLoad {
    [[NSNotificationCenter defaultCenter] removeObserver:self.audioStartObserver];
    self.audioStartObserver = nil;

     // ...
}

Using weak reference to self will not remove the observer. This will just allow to dealloc your view controller. But observer blocks will still be in notification center. And they will be called each time.

Upvotes: 1

Wain
Wain

Reputation: 119041

Because you are using the notification methods which take a block argument and you use a strong reference to self in the block. You should use the observation method which uses a callback selector (so there is no capture) or create a __weak reference to self to use in the blocks.

Upvotes: 6

Related Questions