1

I'm have the following code:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillEnterFullscreen:)
                                             name:MPMoviePlayerWillEnterFullscreenNotification
                                           object:nil];

And the method uses a property of self:

- (void)moviePlayerWillEnterFullscreen:(NSNotification *)notification
{
    NSLog(@"%@", self.videoItem._id);
}

Sometimes (not always) the self object inside the handler is a different object (and an uninitialized one which causes a crash)

I can't seem to figure out what am I doing wrong, and how to avoid this case. Is the "self" object gets copied?

Boaz
  • 4,864
  • 12
  • 50
  • 90
  • 2
    Did you remember to remove this self as an observer before it was deallocated? – Mick MacCallum Feb 12 '15 at 20:07
  • Are you ever calling this from a class method? – David Hoelzer Feb 12 '15 at 20:08
  • @0x7fffffff - hmmm... actually not - so what I'm getting is probably a deallocated object... So with the fact I'm doing addObserver in a `viewDidLoad` of a `viewController`. Where should I unregister? – Boaz Feb 12 '15 at 20:23
  • 1
    @Boaz `dealloc` could work, although I tend to add/remove observers in `viewDidAppear:` / `viewWillDisappear:` (Just do what's right for your app) – Mick MacCallum Feb 12 '15 at 20:28

1 Answers1

4

Echoing @0x7fffffff's comment, if you register an observation, you almost always want to have:

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

There is (usually) little cost to removing yourself from the notification center, and it does not care if you are an observer or not, so this is good insurance that I recommend for any object that ever observes an notification.

(Removing yourself as an observer is O(n) in the total number of registered observations in the center. So if you have thousands of notification observations, then removeObserver: can take nontrivial time, but so will postNotification:. In this case, you generally should reduce how many observations you make rather than avoid using removeObserver:.)

Following up on your comment, you almost never want to use addObserver: in viewDidLoad. You almost always want to do it in viewDidAppear: and remove yourself as an observer in viewWillDisappear: (or viewWillAppear:/viewDidDisappear:, whichever is convenient), and also in dealloc as a safety. It is almost always incorrect to be observing notifications in a view controller that is not currently onscreen.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Sorry to bother, but why (viewDidAppear,viewWillDisappear) or viewWillAppear:/viewDidDisappear:? are they preferred combination? Can I use it as (viewWillAppear,viewWillDisappear)? – gabbler Feb 15 '15 at 08:04
  • Typically you want to keep things symmetric to make them easier to think about. DidAppear/WillDisappear are for things that require being on screen (animations for instance). WillAppear/DidDisappear are for things that want to happen offscreen (setting up data before its shown; since you don't want flicker). Many things don't care and could go either place, but it's wise to have clarity about which you're using and to keep things balanced and symmetrical. It doesn't matter until it matters a lot, so consistency is cheap insurance. – Rob Napier Feb 15 '15 at 14:53