iOS KVO 的本质探究

2023-04-16  本文已影响0人  笔头还没烂

一、先看结论,如下:

  1. 屏蔽内部实现,隐藏了 NSKVONotifying_XXX 类的存在,示例代码如下:

    //屏蔽内部实现,隐藏了 NSKVONotifying_XXX 类的存在, XXX 代表原始类的类名
    - (Class)class{
         return [XXX class];
    }
    
  2. 重写了属性的 setter 方法,如属性为 age,则示例代码如下:

    - (void)setAge:(int)age {
         __NSSetIntValueAndNotify();
    }
    
  3. 重写了 dealloc 方法,完成类的收尾工作

  4. isKVO 方法,示例代码如下:

    - (BOOL)_isKVO {
         return YES:
    }
    

二、为什么是上面这四个方法?猜测添加了KVO 监听的实例对象 isa 指针所指向的类对象中的方法列表都有哪些方法?

尝试证明,代码如下:

  1. Person 类的代码:
  1. ViewController.m 的代码
#import "ViewController.h"
#import <objc/runtime.h>
#import "Person.h"

@interface ViewController ()
@property (nonatomic,strong) Person *person1;
@property (nonatomic,strong) Person *person2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.person1 = [[Person alloc] init];
    self.person1.age = 10;
    
    self.person2 = [[Person alloc] init];
    self.person2.age = 20;
    
    //给 person 对象添加 KVO监听
    [self.person1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    [self showMethodListOfClass:object_getClass(self.person1)];
    [self showMethodListOfClass:object_getClass(self.person2)];
    
}
//传入一个类对象,并遍历该类对象中的方法列表,并将方法列表打印出来
- (void)showMethodListOfClass:(Class)cls {
    NSMutableString *muStr = [NSMutableString string];
    unsigned int count;
    Method *methodList = class_copyMethodList(cls, &count);
    for (unsigned i = 0; i< count; i++) {
        Method method = methodList[i];
        SEL sel = method_getName(method);
        NSString *methodName =  NSStringFromSelector(sel);
        [muStr appendString:methodName];
        [muStr appendString:@", "];
    }
    NSLog(@"%@",muStr);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person1.age = 20;
}

//当监听对象对象的属性值发生改变时,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"监听到 %@ 的 %@ 属性值改变了 -- %@",object,keyPath,change);
}

- (void)dealloc {
    [self.person1 removeObserver:self forKeyPath:@"age"];
}
@end

程序运行后,输出结果如下:

setAge:, class, dealloc, _isKVOA,

willChangeValueForKey:, didChangeValueForKey:, age, setAge:,

通过上面的运行结果可以看出,添加了 KVO 监听的实例对象 person1,其 isa 所指象的类对象的方法列表有setAge:, class, dealloc, _isKVOA, 四个方法;而没有添加 KVO 监听的实例对象 person2 其 isa 所指象的类对象的方法列表是 age 属性所生成的 getter 和 setter 方法,同时还有 willChangeValueForKey:, didChangeValueForKey: 的方法。

上一篇 下一篇

猜你喜欢

热点阅读