设为首页 加入收藏

TOP

【OC底层】KVO原理(二)
2019-08-31 00:22:09 】 浏览:71
Tags:底层 KVO 原理

通过输出结果可以发现person1的setAge已经被重写了,改成了调用Foundation框架中C语言写的 _NSSetIntValueAndNotify 方法,

还有一点,监听的属性值类型不同,调用的方法也不同,如果是NSString的,就会调用 _NSSetObjectValueAndNotify 方法,会有几种类型

大家都知道苹果的代码是不开源的,所以我们也不知道 _NSSetIntValueAndNotify 这个方法里面到底调用了些什么,那我们可以试着通过其它的方式去猜一下里面是怎么调用的。

KVO底层的调用顺序

我们先对我们自定义的类下手,重写下类里面的几个方法:

类实现:

#import "XGPerson.h"

@implementation XGPerson

- (void)setAge:(int)age{ _age = age; NSLog(@"XGPerson setAge"); } - (void)willChangeva lueForKey:(NSString *)key{ [super willChangeva lueForKey:key]; NSLog(@"willChangeva lueForKey"); } - (void)didChangeva lueForKey:(NSString *)key{ NSLog(@"didChangeva lueForKey - begin"); [super didChangeva lueForKey:key]; NSLog(@"didChangeva lueForKey - end"); }

重写上面3个方法来监听我们的值到底是怎么被改的,KVO的通知回调又是什么时候调用的

我们先设置KVO的监听回调

// KVO监听回调
- (void)observeva lueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    NSLog(@"监听到%@的%@属性值改变了 - %@", object, keyPath, change[@"new"]);
}

 

我们直接修改person1的age值,触发一下KVO,输出如下:

2018-11-02 15:38:24.788395+0800 KVO原理[4298:186471] willChangeva lueForKey
2018-11-02 15:38:24.788573+0800 KVO原理[4298:186471] XGPerson setAge
2018-11-02 15:38:24.788696+0800 KVO原理[4298:186471] didChangeva lueForKey - begin
2018-11-02 15:38:24.788893+0800 KVO原理[4298:186471] 监听到<XGPerson: 0x60400022f420>的age属性值改变了 - 2
2018-11-02 15:38:24.789014+0800 KVO原理[4298:186471] didChangeva lueForKey - end

从结果中可以看出KVO是在哪个时候触发回调的,就是在 didChangeva lueForKey 这个方法里面触发的

NSKVONotifying_XGPerson子类的研究

接下来我们再来研究下之前上面说的那个 NSKVONotifying_XGPerson 子类,可能大家会很好奇这里面到底有些什么东西,下面我们就使用runtime将这个子类的所有方法都打印出来

我们先写一个方法用来打印一个类对象的所有方法,代码如下:

// 获取一个对象的所有方法
- (void)getMehtodsOfClass:(Class)cls{
    
    unsigned int count;
    Method* methods = class_copyMethodList(cls, &count);
    
    NSMutableString* methodList = [[NSMutableString alloc]init];
    for (int i=0; i < count; i++) {
        Method method = methods[i];
        NSString* methodName = NSStringFromSelector(method_getName(method));
        [methodList appendString:[NSString stringWithFormat:@"| %@",methodName]];
    }
    NSLog(@"%@对象-所有方法:%@",cls,methodList);

   // C语言的函数是需要手动释放内存的喔
   free(methods);

}

下面使用这个方法打印下person1的所有方法,顺便我们再对比下 object_getClass 和 class

    // 一定要使用 object_getClass去获取类对象,不然获取到的不是真正的那个子类,而是XGPperson这个类
    [self getMehtodsOfClass:object_getClass(self.person1)];

   // 使用 class属性获取的类对象 [self getMehtodsOfClass:[self.person1 class]];

输出:

2018-11-02 15:45:07.918209+0800 KVO原理[4369:190437] NSKVONotifying_XGPerson对象-所有方法:| setAge:| class| dealloc| _isKVOA
2018-11-02 15:45:07.918371+0800 KVO原理[4369:190437] XGPerson对象-所有方法:| .cxx_destruct| name| willChangeva lueForKey:| didChangeva lueForKey:| setName:| setAge:| age

通过结果可以看出,这个子类里面就是重写了3个父类方法,还有一个私有的方法,我们XGPerson这个类还有一个name属性,这里为什么没有setName呢?因为我们没有给 name 属性添加KVO,所以就不会重写它,这里面确实有那个 class 方法,确实被重写了,所以当我们使用 [self.person1 class] 的方式的时候它内部怎么返回的就清楚了。

NSKVONotifying_XGPerson 伪代码实现

通过上面的研究,我们大概也能清楚NSKVONotifying_XGPerson这个子类里面是如何实现的了,大概的代码如下:

头文件:

@interface NSKVONotifying_XGPerson : XGPerson

@end

实现:

#import "NSKVONotify
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇iOS开发之OC与swift开发混编教程.. 下一篇给button增加下划线

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目