一、基本概念
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
