一:KVO: 键值观察
是基于键值编码实现的一种观察者机制,其实现依赖于 Objective-C 强大的 Runtime,当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法随后负责通知观察对象属性的改变状况。
Apple 使用了 isa-swizzling 来实现 KVO 。当观察对象A时,KVO机制动态创建一个新的名为:NSKVONotifying_A的新类,该类继承自对象A的本类,且 KVO 为 NSKVONotifying_A重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。
KVO的使用:
1、创建观察对象,在当前类中监测searchString这个字段值是否发生改变
[self addObserver:self forKeyPath:@"searchString" options:NSKeyValueObservingOptionNew context:nil];
2、获取监听,当searchString这个字段值发生改变后,会调用该方法.$\color{red}{r如果searchString为属性,不能使用 _searchString=@"新值" 这种方法改值,需要用 self.searchString=@"新值" 这种方法,否则不会调用下面的方法}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
// keyPath判断是否是当前监听的值
if ([keyPath isEqualToString:@"searchString"]) {
// change[@"new"]获取改变后的值
_searchStr = change[@"new"];
}
}
3、移除观察,一般在dealloc方法里面执行
-(void)dealloc {
[self removeObserver:self forKeyPath:@"searchString"];
}
二:NSNotification通知
是使用观察者模式来实现用于跨层传递消息的机制,传递方式是一对多的
通知 的使用
1、注册监听
//监听searchStringChange字段,如果收到通知调用searchStringChangeNotification方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchStringChangeNotification:) name:@"searchStringChange" object:nil];
-(void)searchStringChangeNotification:(NSNotification *)notification {
//notification.object为searchStringChange 改变后的值
_searchStr = notification.object;
}
2、发送通知
//在searchStringChange字段值改变的地方发送通知,这是就会触发searchStringChangeNotification方法
[[NSNotificationCenter defaultCenter] postNotificationName:@"searchStringChange" object:_searchStringChange];
3、移除通知,一般在dealloc方法里面执行
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
三:使用注意事项
1、如果用通知监听系统的属性,则不需要实现第二步发送通知,如监听键盘事件只需第一步和第三步
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNew:) name:UIKeyboardWillShowNotification object:nil];
2、关于移除。现在基本大家测试环境都是iOS13,发现 KVO和通知的第三步移除不写,也没有任何问题。这里说明下,通知的移除是在iOS9.0及以后可以不写了,如果你的项目支持iOS8.0,你也不写通知移除,那么在8.0版本上就会报错;KVO的移除忘了是在iOS11还是iOS12后才可以不写,否则也会报错。
四:同异步
1、通知和KVO都是同步的,即在调起监听后,执行完监听内容才会执行后续代码。
2、KVO实现异步,创建一个异步线程,将值改变放在里面
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.searchString = @"值改变";
});
3、通知实现异步,创建一个异步线程,将发送通知放在里面,或者处理事件放在里面
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"searchString" object:@"值改变"];
});
或
-(void)searchStringChangeNotification:(NSNotification *)notification {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(3);
NSLog(@"%@",notification.object);
});
}
4、另外,通知的异步可以用NSNotificationQueue,将通知放到通知异步缓冲队列中实现异步操作。将发送通知改成下面代码即可
NSNotification *notification = [NSNotification notificationWithName:@"searchString" object:@"值改变"];
[[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP];
网友评论