iOS知识搜集ios进阶酷iOS事件响应机制

NSNotificationCenter实现原理?

2016-12-21  本文已影响2115人  Vein_

# 前言

Cocoa中使用NSNotification、NSNotificationCenter和KVO来实现观察者模式,实现对象间一对多的依赖关系。

本篇文章主要来讨论NSNotification和NSNotificationCenter


# NSNotification

NSNotification是方便NSNotificationCenter广播到其他对象时的封装对象,简单讲即通知中心对通知调度表中的对象广播时发送NSNotification对象。

@interface NSNotification : NSObject <NSCopying, NSCoding>

@property (readonly, copy) NSNotificationName name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;

NSNotification对象包含名称、object、字典三个属性,名称是用来标识通知的标记,object是要通知的对象可以为nil,字典用来存储发送通知时附带的信息,也可以为nil

# NSNotificationCenter

NSNotificationCenter是类似一个广播中心站,使用defaultCenter来获取应用中的通知中心,它可以向应用任何地方发送和接收通知。在通知中心注册观察者,发送者使用通知中心广播时,以NSNotificationnameobject来确定需要发送给哪个观察者。为保证观察者能接收到通知,所以应先向通知中心注册观察者,接着再发送通知这样才能在通知中心调度表中查找到相应观察者进行通知。

发送者

发送通知可使用以下方法发送通知

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

观察者

你可以使用以下两种方式注册观察者

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;

- (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);
    // The return value is retained by the system, and should be held onto by the caller in
    // order to remove the observer with removeObserver: later, to stop observation.
  1. 第一种方式是比较常用的添加Oberver的方式,接到通知时执行aSelector。
  2. 第二种方式是基于Block来添加观察者,往通知中心的调度表中添加观察者,这个观察者包括一个queue和一个block,并且会返回这个观察者对象。当接到通知时执行block所在的线程为添加观察者时传入的queue参数,queue也可以为nil,那么block就在通知所在的线程同步执行。

这里需要注意的是如果使用第二种的方式创建观察者需要弱引用可能引起循环引用的对象,避免内存泄漏。

移除观察者

在对象被释放前需要移除掉观察者,避免已经被释放的对象还接收到通知导致崩溃。
移除观察者有两种方式:

- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;
__block __weak id<NSObject> observer = [[NSNotificationCenter defaultCenter] addObserverForName:kChangeNotifition object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
       NSLog(@"-[NSNotificationCenter addObserverForName:object:queue:usingBlock:]");
      [[NSNotificationCenter defaultCenter] removeObserver:observer];
   }];

# 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;

发送方式

typedef NS_ENUM(NSUInteger, NSPostingStyle) {
    NSPostWhenIdle = 1,
    NSPostASAP = 2,
    NSPostNow = 3  
};

NSPostWhenIdle:空闲发送通知 当运行循环处于等待或空闲状态时,发送通知,对于不重要的通知可以使用。
NSPostASAP:尽快发送通知 当前运行循环迭代完成时,通知将会被发送,有点类似没有延迟的定时器。
NSPostNow :同步发送通知 如果不使用合并通知 和postNotification:一样是同步通知。

合并通知

typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
    NSNotificationNoCoalescing = 0,
    NSNotificationCoalescingOnName = 1,
    NSNotificationCoalescingOnSender = 2
};

NSNotificationNoCoalescing:不合并通知。
NSNotificationCoalescingOnName:合并相同名称的通知。
NSNotificationCoalescingOnSender:合并相同通知和同一对象的通知。

# NSNotificatinonCenter实现原理

# 参考资料

上一篇下一篇

猜你喜欢

热点阅读