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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM