一、基本概念

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

iOS-NSNotificationCenter通知原理解析的更多相关文章

  1. IOS NSNotificationCenter 通知的使用

    1.注册通知 [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notify) name:@" ...

  2. iOS 10 UserNotification框架解析 – 本地通知

    iOS 10以前的通知比较杂乱,把本地通知和远程通知分开了,诞生了许多功能类似的API,很容易让初学者犯迷糊.而iOS 10的通知把API做了统一,利用独立的UserNotifications.fra ...

  3. IOS中通知中心(NSNotificationCenter)

    摘要 NSNotification是IOS中一个调度消息通知的类,采用单例模式设计,在程序中实现传值.回调等地方应用很广.   IOS中通知中心NSNotificationCenter应用总结 一.了 ...

  4. APPcrawler基础原理解析及使用

    一.背景 一年前,我们一直在用monkey进行Android 的稳定性测试 ,主要目的就是为了测试app 是否会产生Crash,是否会有ANR,页面错误等问题,在monkey测试过程中,实现了脱离Ca ...

  5. [转载]iOS 10 UserNotifications 框架解析

    活久见的重构 - iOS 10 UserNotifications 框架解析 TL;DR iOS 10 中以前杂乱的和通知相关的 API 都被统一了,现在开发者可以使用独立的 UserNotifica ...

  6. 开源磁力搜索爬虫dhtspider原理解析

    开源地址:https://github.com/callmelanmao/dhtspider. 开源的dht爬虫已经有很多了,有php版本的,python版本的和nodejs版本.经过一些测试,发现还 ...

  7. iOS 10 UserNotifications 框架解析

    摘自:https://onevcat.com/2016/08/notification/ iOS 10 中以前杂乱的和通知相关的 API 都被统一了,现在开发者可以使用独立的 UserNotifica ...

  8. iOS - Notification 通知

    1.Notification 通知中心实际上是在程序内部提供了消息广播的一种机制,它允许我们在低程度耦合的情况下,满足控制器与一个任意的对象进行通信的目的.每一个 iOS 程序(即每一个进程)都有一个 ...

  9. IOS的XML文件解析,利用了NSData和NSFileHandle

    如果需要了解关于文档对象模型和XML的介绍,参看 http://www.cnblogs.com/xinchrome/p/4890723.html 读取XML 上代码: NSFileHandle *fi ...

随机推荐

  1. P2532 [AHOI2012]树屋阶梯

    题目:P2532 [AHOI2012]树屋阶梯 思路: 打表之后不难看出是裸的Catalan数.简单证明一下: 对于任意一种合法方案,都可以表示为在左下角先放一个\(k*(n+1-k),k\in[1, ...

  2. Java 内存模型及GC原理 (转)

      来源:http://blog.csdn.net/ithomer/article/details/6252552 一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性 ...

  3. behavior planning——15.cost function design weightTweaking

    Designing cost functions is difficult and getting them all to cooperate to produce reasionable vehic ...

  4. thinkphp 本地配置手机移动端,在pc端访问手机端

  5. Duplicate keys detected: '0'. This may cause an update error.

    在运行vue项目的时候报了:[Vue warn]: Duplicate keys detected: ‘0’. This may cause an update error(错误,检测到重复的key值 ...

  6. APICloud修改最低操作系统版本要求

    在APICloud中的云编译选项中: 点击高级设置,就可以修改对应的操作系统版本要求:

  7. 使用Laravel的队列实现系统通知、

    使用Laravel的队列实现系统通知. 第一步:创建 jobs表的migrate php artisan queue:table 第二步:创建jobs 表 php artisan migrate 第三 ...

  8. 9-6 UVa 11400

    参考 http://www.cnblogs.com/Kiraa/p/5510757.html http://www.cnblogs.com/zhaopAC/p/5159950.html 根据题目说明中 ...

  9. vue iframe嵌套页面高度自适应 (ios 宽度扩大的bug , ios展示比例问题)

    <template>   <div class="card-index pt-relative">     <div id="wrapper ...

  10. JAVA配置系统变量

    CLASSPATH= .;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar JAVA_HOME = C:/Program Files/Java/jdk1 ...