一郎科技|iOS底层系列:KVO( 二 )
3. NSKVONotifying_Person中的setAge:的实现个人感觉 , 挖掘setAge:的实现是比较难的 。
我们通过下面的方法打印一下方法IMP的地址
NSLog(@"person1添加KVO之前的两个setAge地址: \n -person1:%p -- person2:%p",[person1 methodForSelector:@selector(setAge:)],[person2 methodForSelector:@selector(setAge:)]);[person1 addObserver:selfforKeyPath:@"age"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];NSLog(@"person1添加KVO之后的两个setAge地址: \n -person1:%p -- person2:%p",[person1 methodForSelector:@selector(setAge:)],[person2 methodForSelector:@selector(setAge:)]);
输出:
person1添加KVO之前的两个setAge地址: -person1:0x1005ee850 -- person2:0x1005ee850 person1添加KVO之后的两个setAge地址: -person1:0x7fff25623f0e -- person2:0x1005ee850
我们可以看到 , 在添加KVO监听前后 , person2的setAge实现的地址没有发生变化 , 但是person1的变了 , 我们在打印台用lldb命令打印一下0x7fff25623f0e
(lldb) p (IMP)0x7fff25623f0e(IMP) $1 = 0x00007fff25623f0e (Foundation`_NSSetIntValueAndNotify)
可以看到setAge的实现其实就是调用了Foundation框架的_NSSetIntValueAndNotify方法 。 那具体的_NSSetIntValueAndNotify内部实现是怎么样的呢?因为Foundation不开源 , 我们只能猜测 , 并对我们的猜测做出相应的验证 。
下面是我看过一些大神的分析之后猜测的_NSSetIntValueAndNotify实现的 伪代码 (特此鸣谢我们的MJ老师)
void _NSSetIntValueAndNotify() {[self willChangeValueForKey:@"age"];[super setAge:age];[self didChangeValueForKey:@"age"];}- (void)didChangeValueForKey:(NSString *)keyPath {// 通知监听者,已经修改完毕[observer observeValueForKeyPath:keyPath ofObject:self change:nil context:nil];}
如何验证一下我们的猜测呢?
我们知道NSKVONotifying_Person类中没有实现willChangeValueForKey和didChangeValueForKey这两个方法 , 所以我们可以在NSKVONotifying_Person的父类 , 也就是Person类型重写这两个方法 , 改造完之后的Person类里面应该是下面这样子:
@interface Person : NSObject@property (nonatomic, assign) int age;@end@implementation Person- (void)setAge:(int)age {_age = age;NSLog(@"age:%d",age);}- (void)willChangeValueForKey:(NSString *)key {[super willChangeValueForKey:key];NSLog(@"willChangeValueForKey");}- (void)didChangeValueForKey:(NSString *)key {NSLog(@"didChangeValueForKey - begin");[super didChangeValueForKey:key];NSLog(@"didChangeValueForKey - end");}@end
person1在添加了KVO监听 , 并设置值 person1.age = 10; 之后 , 输出如下:
2020-09-07 23:47:13.787066+0800 KVO[8122:119707] willChangeValueForKey2020-09-07 23:47:13.787229+0800 KVO[8122:119707] age:102020-09-07 23:47:13.787334+0800 KVO[8122:119707] didChangeValueForKey - begin2020-09-07 23:47:13.787592+0800 KVO[8122:119707]-- age -- {kind = 1;new = 10;old = 0;}2020-09-07 23:47:13.787732+0800 KVO[8122:119707] didChangeValueForKey - end
输出结果与我们的猜测一致 。
其他小知识点NSKVONotifying_Person也重写了class方法 , 使用[person1 class]的时候返回的是Person , 其实也很容易理解 , 只是为了隐藏NSKVONotifying_Person这个类 , 尽量隐藏KVO的内部实现 。
大家也可以看一下我下面附上的参考文章 , 写的很不错 。
推荐阅读
- 科技日报|塑料微粒影响几何?人类认知仍不足
- 七号人称说科技|华为始料未及?台积电又成了“炮灰”?新风暴说来就来
- 大众新闻|众安科技荣获“今日·保险中介榜”年度Insurtech独角兽
- 雷科技|朋友圈都在秀的“互联网勋章”到底是什么?
- 快科技|小米10至尊纪念版妙享功能升级:手机与Windows电脑合体
- 七号人称说科技|再给华为一颗糖?美国到底在打什么“算盘”?,先给华为一巴掌
- 量子科技,爆发!有项关键技术中国已领先世界
- 暖日科技盈如|这到底是为什么?,俄罗斯华人给出劝告:最好别跟俄罗斯女孩结婚
- 周到|民警利用无人机指挥事故车辆立即撤离 “科技赋能”破解交通管理难题
- 概念股|中国股市:量子科技概念股一览 (名单)