iOS-NSNotificationCenter通知原理解析
一、基本概念
NSNotification
和NSNotificationCenter
是使用观察者模式
来实现的用于跨层传递消息。
NSNotificationCenter采用单例模式。
二、基本实现
通知实现由三个类组成:NSNotificationCenter、NSNotification、NSObserverModel,对应关系和接口设计:
NSNotificationCenter是注册中心,发通知时,发送的是一个NSNotification对象。
NSNotification里面包含发通知需要传递的内容:
name(通知的字符串),
object(发送通知的对象),
userInfo(需要传递的参数),
NSObserverModel是注册通知时需要保持的参数,包括:
observer(观察者对象),
selector(执行的方法),
notificationName(通知名字),
object(携带参数),
operationQueue(队列),
block(回调),
三:原理图:
四:注意点:
1、每次调用addObserver时,都会在通知中心重新注册一次,即使是同一对象,监听同一个消息,而不是去覆盖原来的监听。这样,当通知中心转发某一消息时,如果同一对象多次注册了这个通知的观察者,则会收到多个通知。
2、observer 观察者(不能为nil,通知中心会弱引用,ARC是iOS9之前是unsafe_unretained,iOS9及以后是weak,MRC是assign,所以这也是MRC不移除会crash,ARC不移除不会crash的原因)
五:仿照写一个通知中心:WYNotificationCenter,WYNotification,WYObserverModel
#import <Foundation/Foundation.h> @class WYNotification; NS_ASSUME_NONNULL_BEGIN typedef void(^OperationBlock)(WYNotification *); @interface WYObserverModel : NSObject @property (nonatomic, weak) id observer; //观察者对象 @property (nonatomic, assign) SEL selector; //执行的方法 @property (nonatomic, copy) NSString *notificationName; //通知名字 @property (nonatomic, strong) id object; //携带参数 @property (nonatomic, strong) NSOperationQueue *operationQueue;//队列 @property (nonatomic, copy) OperationBlock block; //回调 @end
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface WYNotification : NSObject @property (readonly, copy) NSNotificationName name; @property (nullable, readonly, retain) id object; @property (nullable, readonly, copy) NSDictionary *userInfo; - (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo; @end NS_ASSUME_NONNULL_END
#import "WYNotification.h" @implementation WYNotification - (instancetype)initWithName:(NSString *)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo { self = [super init]; if (self) { _name = name; _object = object; _userInfo = userInfo; } return self; } @end
#import "WYNotificationCenter.h" #import "WYObserverModel.h" #import "WYNotification.h" @interface WYNotificationCenter() @property(nonatomic,strong)NSMutableDictionary *obsetvers; @end @implementation WYNotificationCenter + (WYNotificationCenter *)defaultCenter { static WYNotificationCenter *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; instance.obsetvers = [NSMutableDictionary dictionary]; }); return instance; } - (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString*)aName object:(nullable id)anObject { // 创建数据模型 WYObserverModel *observerModel = [[WYObserverModel alloc] init]; observerModel.observer = observer; observerModel.selector = aSelector; observerModel.notificationName = aName; observerModel.object = anObject; // 如果不存在,才创建 if (![self.obsetvers objectForKey:aName]) { NSMutableArray *arrays = [NSMutableArray array]; [arrays addObject:observerModel]; // 添加进 json 中 [self.obsetvers setObject:arrays forKey:aName]; } else { // 如果存在,取出来,继续添加进对应数组即可 NSMutableArray *arrays = (NSMutableArray *)[self.obsetvers objectForKey:aName]; [arrays addObject:observerModel]; } } - (id <NSObject>)addObserverForName:(nullable NSString *)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(WYNotification *note))block { WYObserverModel *observerModel = [[WYObserverModel alloc] init]; observerModel.block = block; observerModel.notificationName = name; observerModel.object = obj; observerModel.operationQueue = queue; //如果不存在,那么即创建 if (![self.obsetvers objectForKey:name]) { NSMutableArray *arrays = [[NSMutableArray alloc]init]; [arrays addObject:observerModel]; //填充进入数组 [self.obsetvers setObject:arrays forKey:name]; }else{ //如果存在,取出来,继续添加即可 NSMutableArray *arrays = (NSMutableArray*)[self.obsetvers objectForKey:name]; [arrays addObject:observerModel]; } return nil; } - (void)postNotificationName:(nonnull NSString *)name object:(nullable id)objec { [self postNotificationName:name object:objec userInfo:nil]; }; - (void)postNotificationName:(nonnull NSString *)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo { WYNotification *notification = [[WYNotification alloc] initWithName:name object:object userInfo:userInfo]; [self postNotification:notification]; } - (void)postNotification:(WYNotification *)notification { //name 取出来对应观察者数组,执行任务 NSMutableArray *arrays = (NSMutableArray*)[self.obsetvers objectForKey:notification.name]; NSLog(@"%@",arrays); [arrays enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { //取出数据模型 WYObserverModel *observerModel = obj; id observer = observerModel.observer; SEL secector = observerModel.selector; if (!observerModel.operationQueue) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [observer performSelector:secector withObject:notification]; #pragma clang diagnostic pop }else{ //创建任务 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ //这里用block回调出去 observerModel.block(notification); }]; // 如果添加观察者 传入 队列,那么就任务放在队列中执行(子线程异步执行) NSOperationQueue *operationQueue = observerModel.operationQueue; [operationQueue addOperation:operation]; } }]; } #pragma mark - 移除通知 - (void)removeObserver:(nonnull id)observer { [self removeObserver:observer name:nil object:nil]; } - (void)removeObserver:(nonnull id)observer name:(nullable NSString *)name object:(nullable id)object { // 移除观察者 - 当有 name 参数时 if (name.length > 0 && [self.obsetvers objectForKey:name]) { NSMutableArray *arrays = (NSMutableArray *)[self.obsetvers objectForKey:name]; [arrays removeObject:observer]; } else { // 移除观察者 - 当没有 name 参数时 if (self.obsetvers.allKeys.count > 0 && self.obsetvers.allValues.count > 0) { NSArray *allKeys = self.obsetvers.allKeys; for (int i = 0; i < allKeys.count; i++) { NSMutableArray *keyOfAllObservers = [self.obsetvers objectForKey:allKeys[i]]; BOOL isStop = NO; // 如果找到后就不再遍历后面的数据了 for (int j = 0; j < keyOfAllObservers.count; j++) { // 取出数据模型 WYObserverModel *observerModel = keyOfAllObservers[j]; if (observerModel.observer == observer) { [keyOfAllObservers removeObject:observerModel]; isStop = YES; break; } } if (isStop) { // 找到了,退出循环 break; } } } else { NSAssert(false, @"当前通知中心没有观察者"); } } } @end
六、参考:
https://www.jianshu.com/p/2c9fef32a383
https://blog.csdn.net/m0_37182854/article/details/78782724