iOS Remove observer from notification: Can I call this once for all observers? And even if there are none?

ios, nsnotificationcenter, objective-c

Solution

Yes, that will remove all registrations where the observer is `self`. It's documented in the NSNotificationCenter Class Reference:

The following example illustrates how to unregister `someObserver` for all notifications for which it had previously registered:

[[NSNotificationCenter defaultCenter] removeObserver:someObserver];

Note that in theory (but not, as far as I know, in practice as of iOS 7.0), `UIViewController` could have its own registrations that it doesn't want removed in `viewWillDisappear:`. It's unlikely to register for any of the notifications in the public API using `addObserver:selector:name:object:`, because that would preclude you registering for them in your `UIViewController` subclass, but it could certainly register for non-public notifications now or in a future version.

A safe way to deregister is to send `removeObserver:name:object:` once for each registration:

- (void)deregisterForKeyboardNotifications {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
    [center removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
}

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

- (void)dealloc {
    [self deregisterForKeyboardNotifications];
}

Another way is to use `addObserverForName:object:queue:usingBlock:` to register (instead of `addObserver:selector:name:object:`). This returns a new observer object reference for each registration. You have to save these away (perhaps in an `NSArray` instance variable if you don't want to create individual instance variables). Then you pass each one to `removeObserver:` to deregister its notification. Example:

@implementation MyViewController {
    NSMutableArray *observers;
}

- (void)registerForKeyboardNotifications {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    __weak MyViewController *me = self;
    observers = [NSMutableArray array];
    [observers addObject:[center addObserverForName:UIKeyboardWillShowNotification
        object:nil queue:queue usingBlock:^(NSNotification *note) {
            [me keyboardWillShow:note];
        }]];
    [observers addObject:[center addObserverForName:UIKeyboardWillHideNotification
        object:nil queue:queue usingBlock:^(NSNotification *note) {
            [me keyboardWillHide:note];
        }]];
    [observers addObject:[center addObserverForName:UIApplicationWillResignActiveNotification
        object:nil queue:queue usingBlock:^(NSNotification *note) {
            [me applicationWillResignActive:note];
        }]];
}

- (void)deregisterForKeyboardNotifications {
    for (id observer in observers) {
        [[NSNotificationCenter defaultCenter] removeObserver:observer];
    }
    observers = nil;
}

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

- (void)dealloc {
    [self deregisterForKeyboardNotifications];
}

Since every observer returned by `addObserverForName:object:queue:usingBlock:` is a new object that has only one registration, each call to `removeObserver:` is guaranteed to only remove that observer's one registration.

Update for iOS 9 / macOS 10.11 and later

As of iOS 9 and macOS 10.11, `NSNotificationCenter` automatically deregisters an observer if the observer is deallocated. It is no longer necessary to deregister yourself manually in your `dealloc` method (or `deinit` in Swift) if your deployment target is iOS 9 or later or macOS 10.11 or later.

Problem

I'm registering three observers in most of my view controllers. Some have more, some less but I want to include part of the registration and unregistration process in a parent class. Is there any problem with calling the unregistering even if there is no observer? And is one call to unregister enough for all three observers? ``` - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterBackground:) name:UIApplicationWillResignActiveNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; //Has to be unregistered always, otherwise nav controllers down the line will call this method [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } ```

Original source