首页 > 技术文章 > iOS-NSNotificationCenter通知原理解析

miaomiaocat 2019-10-15 16:34 原文

一、基本概念

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

 

推荐阅读