• iOS-NSNotificationCenter通知原理解析


    一、基本概念

    NSNotificationNSNotificationCenter是使用观察者模式来实现的用于跨层传递消息。

    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

  • 相关阅读:
    C/C++ 构造函数不能是虚函数
    C/C++ STL迭代器失效
    Linux fork函数
    算法和数据结构 限流算法
    数据库 redis底层实现
    C/C++ 虚析构函数
    万物皆可 Serverless 之使用云函数 SCF 快速部署验证码识别接口
    万物皆可 Serverless 之使用云函数 SCF+COS 免费运营微信公众号
    腾讯云云函数 SCF 日志检索最佳实践
    江娱互动「世界争霸」产品迁移至腾讯云云函数的实践
  • 原文地址:https://www.cnblogs.com/miaomiaocat/p/11678591.html
Copyright © 2020-2023  润新知