1. preface

There is a message broadcast mechanism in the OC that sends messages to Observe registered with the Notification Center. The flow can be simply illustrated in the following figure.

  1. The Observer registers with the Notification Center
  2. Poster sends a message to the Notification Center
  3. The Notification Center finds the Dispatch table maintained by the Notification Center according to the messages sent by the Poster
  4. If the corresponding Observer finds a message that it needs, the message is broadcast to the Observer
  5. The Observer receives the message and executes the corresponding Action
  6. Notification Center Removed the Observer

In the message Notification mechanism, three roles need to be paid attention to: Notification Center, Observer and Poster.

  • The Notification Center is a message Notification mechanism that broadcasts messages to registered observers.
  • The Observer registers with the Notification Center, accepts the corresponding message, and performs the corresponding action after receiving the message.
  • Poster sends the message to the Notification Center.

Note that each running app has a Notification Center named defaultCenter. You can also create a new Notificaion Center. In addition, the Notification Center can deliver messages within a program or across multiple processes. If you need in the process of multiple delivery notice, you can use NSDistributedNotificationCenter.

2. addObserver

You can add an Observer to the Notification Center as follows.

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject; Observer: observer object selector: after receiving messages execution method, and this method is only one parameter form such as: - (void) acceptNotificationAction (noic NSNotification *); Name: Message name. When nil, it is not used as a matching attribute in the search dispatch table. Obejct: Which object sends a message to receive, when nil, not as a match attribute for the search Dispatch table.Copy the code
- (id<NSObject>)addObserverForName:(NSNotificationName)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block; Name: Message name. When nil, it is not used as a matching attribute in the search dispatch table. Object: Which object to receive the message from. If it is nil, it is not used as the matching attribute of the search Dispatch table. Queue: Specifies the running queue of the block. When queue is nil, the block defaults to run synchronously on the thread of poster usingBlock: the executing block, which can be understood as an Observer block. This method returns an opaque object that represents an observer. Notification Center holds this object until the Observer registration is removed.Copy the code

When you use addObserverForName (NSNotificationName) Name Object (ID)obj Queue (NSOperationQueue *)queue usingBlock (void The (^)(NSNotification *note))block method registers an observer and receives a message only once. You can use the following code.

NSNotificationCenter * __weak center = [NSNotificationCenter defaultCenter];
id __block token = [center addObserverForName:@"OneTimeNotification"
                                       object:nil
                                        queue:[NSOperationQueue mainQueue]
                                   usingBlock:^(NSNotification *note) {
                                       NSLog(@"Received the notification!");
                                       [center removeObserver:token];
                                   }];
Copy the code

3. removeObserver

To remove an observer from the Notification Center and no longer receive message notifications, use the following method.

- (void)removeObserver:(id)observer name:(NSNotificationName)aName object:(id)anObject; Observe: Observer. Remove the observer from the dispacth table as observer. AName: message name Remove the entry with the message name aName from dispacth table. If it is nil, it is not used as the matching attribute of the search Dispatch table. AnObject: indicates the object that sends messages. Dispacth Table removes the item whose object sends messages is anObject. If it is nil, it is not used as the matching attribute of the search Dispatch table.Copy the code
- (void)removeObserver:(id)observer; Observer: Indicates the observer object. The observer object is removed from the Dispacth table.Copy the code

When you removeObserver, you must ensure that the specified object in the addObserve method exists. When you use (iOS 9.0 and later, MacOS 10.11 and later) addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName Object :(id)anObject register as an observer. You do not need to use removerObserver to unregister the observer. The system will remove it the next time it sends a message to it. When you unregister observer, if you specify the name of the message and the sender of the message when you register observer, it is best to use the following method when unregister Observer.

- (void)removeObserver:(id)observer name:(NSNotificationName)aName object:(id)anObject; Observe: Observer. Remove the observer from the dispacth table as observer. AName: message name Remove the entry with the message name aName from dispacth table. If it is nil, it is not used as the matching attribute of the search Dispatch table. AnObject: indicates the object that sends messages. Dispacth Table removes the item whose object sends messages is anObject. If it is nil, it is not used as the matching attribute of the search Dispatch table.Copy the code

4. postNotification

There are three ways to send a message to the Notification Center. And the easiest way to do that is

- (void)postNotification:(NSNotification *)notification;
Copy the code

The second way is to specify the message name, the message sender, and additional information about the message.

- (void)postNotificationName:(NSNotificationName)aName 
                      object:(id)anObject 
                    userInfo:(NSDictionary *)aUserInfo;
Copy the code

The last one is equivalent to setting the argument aUserInfo to nil for the second method of sending messages.

Copy the code
- (void)postNotificationName:(NSNotificationName)aName 
                      object:(id)anObject;
Copy the code

5. Code practices

Define the following two classes NotificationA and NotificationB. The class NotificationA is defined as follows:

//NotificationA.h 

#ifndef NotificationA_h
#define NotificationA_h

@class NotificationB;

@interface NotificationA : NSObject

@property (weak) NotificationB *B;

- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;

@end

#endif /* NotificationA_h */
Copy the code

//NotificationA.m 

#import <Foundation/Foundation.h>
#import "NotificationA.h"
#import "NotificationB.h"

@implementation NotificationA

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:self];
}

- (void)activeForNotification:(NSNotification *)notification{
    NSLog(@"Accept notificaion from B");
}

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"B Send" object:nil];
}

@end

Copy the code

The class NotificationB is defined as follows:

// NotificationB.h

#ifndef NotificationB_h
#define NotificationB_h

@class NotificationA;

@interface NotificationB : NSObject

@property (weak) NotificationA *A;

- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;

@end

#endif /* NotificationB_h */

Copy the code
// NotificationB.m

@implementation NotificationB

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:self];
}

- (void)activeForNotification:(NSNotification *)notification{
    NSLog(@"Accept notificaion from A");
}

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"A Send" object:self.A];
}

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"A Send" object:nil];
}

@end
Copy the code

Both classes have the following four methods.

- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;
Copy the code

Firstly, NotificationA object is used as Observer and NotificationB as Nofication Poster. The main function looks like this:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    
    [A addOberver];
    [B postNotification];
    return 0;
}
Copy the code

In the addObserver class NotificationA, the register Observer code is as follows: Name is not null, object is null.

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}
Copy the code

In postNotification of class NotificationB, name is not null, nor is object.

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:self];
}
Copy the code

The output is as follows: You can see that the Observer received the message and executed the activeForNotification method.

If name is not null in the postNotification of class NotificationB, object is also null.

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:nil];
}
Copy the code

The output is as follows: You can see that the Observer received the message and executed the activeForNotification method.

When a Notification name is specified in a Register Observer, and when a Notification is posted, notificaion poster is specified or not. All observers receive messages

Then we specify the object to send the message when we addobserver and do not specify notification name. The addObserver function of class NotificationA is as follows:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:nil object:self.B];
}
Copy the code

In this case, the postNotificaion function of class NotificationB is as follows: Object is specified as self and Notification name is nil.

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:“B Send” object:self];
}
Copy the code

The output is as follows: You can see that the Observer received the message and executed the activeForNotification method.

However, if the Notification name is nil, the compiler will only give a warning (the argument is a non-null argument), but the Observer will not receive the message. The code is as follows:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:nil object:self];
}
Copy the code

The output is as follows: You can see that the Observer did not receive the message.

If the postNotification method is not specified or does not correspond to the specified Notificaion poster, the message cannot be received.

- (void)postNotification{ [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:nil]; } or - (void)postNotification{[[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" Object :[[NSString alloc] init]]; }Copy the code

When register Observer, object is specified but Notification name is not specified. When a Notification is posted, the Notification name must be specified and the Poster object must be the same as that specified by register obberver so that the Observer can receive the message

We can use removerObserver to unregister the Observer. When removerObserver specifies the Notification name, whether or not object is specified for addObserver. All entries in the Dispatch table that contain the Notification name will be removed. The code for addObserver in class NotificationA is as follows:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:self.B];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}
Copy the code

The code for the removeObserver method in NotificationA is as follows:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"B Send" object:nil];
}
Copy the code

The postNotification method code of class NotificationB is as follows:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:[[NSString alloc] init]];
}
Copy the code

The mian function code is as follows:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    
    [A addOberver];
    [A removeObserve];
    [B postNotification];
    return 0;
}
Copy the code

The result is as follows: No output is displayed. If a Notification name is specified in removeObserver, all entries containing the Notification name in the Dispatch table will be removed.

When removerObserver specifies a Poster object, the code for the addObserver class NotificationA is as follows:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:nil object:self.B];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:self.B];
}
Copy the code

The code for the removeObserver method in NotificationA is as follows:

- (void)removeObserver{[[NSNotificationCenter defaultCenter] removeObserver:self name:@ "Test" object:self.B]; }Copy the code

The postNotification method code of class NotificationB is as follows:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:self]];
}
Copy the code

The mian function code is as follows:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    
    [A addOberver];
    [A removeObserve];
    [B postNotification];
    return 0;
}
Copy the code

The result is as follows: removeObserver does not take effect and the Observer still receives the message.

When the removeObserver code is as follows: NotificationA removeObserver method code is as follows:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:self.B];
}
Copy the code

The result is as follows: You can see that the Observer was removed and no message was received. The rule for removeObserver to remove messages is as follows: Specify object and name, search for items in the Dispatch table, and the items that match the two items are removed. Otherwise, it is not removed. If only name or object is specified, the dispatch table is searched for items that meet this requirement and removed.The removeObserver code should be rewritten as follows:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:[[NSString alloc] init] name:nil object:self.B];
}
Copy the code

The result is as follows: If the removeObserver method specifies an observer object and the dispatch table does not find the corresponding entry, the Observer cannot be removed.

Summary: The Dispatch table contains three matches:

  • Observer
  • Notification Name
  • Notification Poster

The Observer can be removed from the Dispatch table only when the three items specified by the Register Observer meet the requirements specified by the Remove Observer. That is, the Observer cannot receive messages. When the three items specified by the Register Observer, when you specify notification name and Notification, the two items specified by the postNotification need to be the same. However, if only Notification or Notification poster is specified, postNotification can receive messages as long as the corresponding items are consistent.

6 summarizes

  1. The Notification Center maintains a Dispatch table, with three major items including Observer, notification and Notification Poster.
  2. When these items are specified by addObserver, the items specified by removerObserver must correspond to the items specified by addObserver before they can be removed from the Dispatch Table.
  3. When the addObserver specifies that the Notification Name and poster object are not null, the postNotification must be the same for the Observer to receive the message. When only notificationName is specified, the Poster Object is null. The Notification name parameter of postNotification must be the same as the notification name parameter of postNotification, and the object parameter can be arbitrary. When only a Poster object is specified. The Notification name of the postNotification (which is a non-null argument) must be specified and poster OBEjct must be the same for the Observer to accept the message.