iOS中通知中心NSNotificationCenter的使用
NSNotificationCenter(通知)的使用方法
- 首先了解下了几个相关的类
1、NSNotification: 这个类是方便NSNotificationCenter广播到其他对象时的封装对象,简单讲即通知中心对通知调度表中的对象广播时发送NSNotification对象。
2、NSNotification:包含名称、object、字典三个属性,名称是用来标识通知的标记,object是要通知的对象可以为nil,字典用来存储发送通知时附带的信息,也可以为nil。
(1):@property (readonly, copy) NSNotificationName name;
(2):@property (nullable, readonly, retain) id object;
(3):@property (nullable, readonly, copy) NSDictionary *userInfo;
- 下面给出几种创建NSNotification的方法
不需要传值的方法
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
可以传值的方法
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
- NSNotificationCenter 是类似一个广播中心站,使用defaultCenter(单例模式)来获取应用中的通知中心,它可以向应用任何地方发送和接收通知。在通知中心注册观察者,发送者使用通知中心广播时,以NSNotification的name和object来确定需要发送给哪个观察者。为保证观察者能接收到通知,所以应先向通知中心注册观察者,接着再发送通知这样才能在通知中心调度表中查找到相应观察者进行通知。
以下是NSNotificationCenter 的创建方法:
1:注册观察者的两种方法
第一种方式是比较常用的添加Oberver的方式,接到通知时执行aSelector。
(1):- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
第二种方式是基于Block来添加观察者,往通知中心的调度表中添加观察者,这个观察者包括一个queue和一个block,并且会返回这个观察者对象。当接到通知时执行block所在的线程为添加观察者时传入的queue参数,queue也可以为nil,那么block就在通知所在的线程同步执行。
这里需要注意的是如果使用第二种的方式创建观察者需要弱引用可能引起循环引用的对象,避免内存泄漏。
(2):- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0);
2:发送通知的方法如下:
发送通知通过name和object来确定来标识观察者,name和object两个参数的规则相同即当通知设置name为ChangeNotifition时,那么只会发送给符合name为ChangeNotifition的观察者,同理object指发送给某个特定对象通知,如果只设置了name,那么只有对应名称的通知会触发。如果同时设置name和object参数时就必须同时符合这两个条件的观察者才能接收到通知。
(1):- (void)postNotification:(NSNotification *)notification;
(2):- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
(3):- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
3:移除通知的方法(移除通知需要在创建发送通知时移除):
在对象被释放前需要移除掉观察者,避免已经被释放的对象还接收到通知导致崩溃。
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;
- 接下来就实现下通知发送消息(这里以不带参数的通知为例):
1:先注册监听者
//监听
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti) name:@"noti1" object:nil];
2:通过UIButton的点击事件触发创建发送通知:
//创建发送消息是需要接受对象已存在
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti1" object:nil];
3:打印接收到的通知信息
-(void)noti{
NSLog(@"接收 不带参数的消息");
}
4:移除通知
-(void)dealloc{
//移除观察者,Observer不能为nil
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
NSNotificatinonCenter实现原理
NSNotificatinonCenter是使用观察者模式来实现的用于跨层传递消息,用来降低耦合度。
NSNotificatinonCenter用来管理通知,将观察者注册到NSNotificatinonCenter的通知调度表中,然后发送通知时利用标识符name和object识别出调度表中的观察者,然后调用相应的观察者的方法,即传递消息(在Objective-C中对象调用方法,就是传递消息,消息有name或者selector,可以接受参数,而且可能有返回值),如果是基于block创建的通知就调用NSNotification的block。
NSNotificationQueue
(这里是借鉴别人的理解,求表打脸)
NSNotificationQueue通知队列,用来管理多个通知的调用。通知队列通常以先进先出(FIFO)顺序维护通。NSNotificationQueue就像一个缓冲池把一个个通知放进池子中,使用特定方式通过NSNotificationCenter发送到相应的观察者。下面我们会提到特定的方式即合并通知和异步通知。
创建通知队列方法:
- (instancetype)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER;
往队列加入通知方法:
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle;
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSRunLoopMode> *)modes;
移除队列中的通知方法:
- (void)dequeueNotificationsMatching:(NSNotification *)notification coalesceMask:(NSUInteger)coalesceMask;
发送方式
NSPostingStyle包括三种类型:
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1,
NSPostASAP = 2,
NSPostNow = 3
};
NSPostWhenIdle:空闲发送通知 当运行循环处于等待或空闲状态时,发送通知,对于不重要的通知可以使用。
NSPostASAP:尽快发送通知 当前运行循环迭代完成时,通知将会被发送,有点类似没有延迟的定时器。
NSPostNow :同步发送通知 如果不使用合并通知 和postNotification:一样是同步通知。
合并通知
NSNotificationCoalescing也包括三种类型:
typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
NSNotificationNoCoalescing = 0,
NSNotificationCoalescingOnName = 1,
NSNotificationCoalescingOnSender = 2
};
NSNotificationNoCoalescing:不合并通知。
NSNotificationCoalescingOnName:合并相同名称的通知。
NSNotificationCoalescingOnSender:合并相同通知和同一对象的通知。
通过合并我们可以用来保证相同的通知只被发送一次。
forModes:(nullable NSArray<NSRunLoopMode> *)modes可以使用不同的NSRunLoopMode配合来发送通知,可以看出实际上NSNotificationQueue与RunLoop的机制以及运行循环有关系,通过NSNotificationQueue队列来发送的通知和关联的RunLoop运行机制来进行的。