KVO 的本质?

  1. iOS 用什么方式实现对一个对象的 KVO ? (KVO 的本质是什么?)
  • 首先利用 Runtime API 动态创建一个中间类(NSKVONotifying_ + 类名), 并让实例对象的 isa 指针指向这个中间类, 当修改实例对象的属性时, 会调用 Foundation 的 _NSSetxxxValueAndNotify 函数, 该函数内部主要是做 willChangeValueForKey, super 的 setter, didChangeValueForKey, 然后会触发 Observer 监听方法
  1. 如何手动触发 KVO?
  • 实例对象先调用 willChangeValueForKey, 然后再调用 didChangeValueForKey
  1. KVO 是否可以添加成员变量的观察?
  • 可以的, 为成员变量添加 KVO 是可以的但是必须用 KVC 方式赋值

具体观察代码, 重点observeValueForKeyPath:

#import "ViewController.h"
#import "Person.h"
#import <objc/runtime.h>

/**
 * 1. iOS 用什么方式实现对一个对象的 KVO ? (KVO 的本质是什么?)
 * 首先利用 Runtime API 动态创建一个中间类(NSKVONotifying_ + 类名), 并让实例对象的 isa 指针指向这个中间类, 当修改实例对象的属性时, 会调用 Foundation 的 _NSSetxxxValueAndNotify 函数, 该函数内部主要是做 willChangeValueForKey, super 的 setter, didChangeValueForKey, 然后会触发 Observer 监听方法
 * 2. 如何手动触发 KVO?
 * 实例对象先调用 willChangeValueForKey, 然后再调用 didChangeValueForKey
 */

@interface ViewController ()

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

@implementation ViewController


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

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.person1 = Person.new;
    self.person1.age = 10;
    self.person2 = Person.new;
    self.person2.age = 20;
    
    // 添加监听
    [self.person1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person1.age = arc4random() % 100 + 1;
    self.person2.age = arc4random() % 100 + 1;
}

// 当监听对象的属性值改变时, 就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    /**
     * 打印 person1 的类对象
     * (lldb) p self.person1.isa
     * (Class) $2 = NSKVONotifying_Person
     * Fix-it applied, fixed expression was:
     * self.person1->isa
     *
     * 打印 person2 的类对象
     * (lldb) p self.person2.isa
     * (Class) $3 = Person
     * Fix-it applied, fixed expression was:
     * self.person2->isa
     *
     * 打印所有方法, 可以 llbd 也可以自己实现一个 _printMethodNamesOfClass
     * (lldb) po [$2 _shortMethodDescription]
     * <NSKVONotifying_Person: 0x600000d40870>:
     * in NSKVONotifying_Person:
     *   Instance Methods:
     *      - (void) setAge:(long)arg1; (0x7fff258e518d)        //  ----- 实际会先调用 _NSSetIntValueAndNotify
     *      - (Class) class; (0x7fff258e2fd5)           //  ----- 重写 class 实现, class 方法 底层可能就是 object_getClass, 重写后让读者认为还是 Person 类
     *      - (void) dealloc; (0x7fff258e2d3a)      // ---- 收尾工作
     *      - (BOOL) _isKVOA; (0x7fff258e2d32)
     *   in Person:
     *      Properties:
     *          @property (nonatomic) long age;  (@synthesize age = _age;)
     *      Instance Methods:
     *          - (long) age; (0x10e795f90)
     *          - (void) setAge:(long)arg1; (0x10e795fb0)
     *   (NSObject ...)
     */

    [self _printMethodNamesOfClass:object_getClass(object)];
    NSLog(@"%@", change);
}

// 打印所有方法
- (void)_printMethodNamesOfClass:(Class)cls {
    // 定义
    unsigned int outCount = 0;
    Method *methodList = NULL;
    Method tempMethod = NULL;
    NSMutableString *strResult = [NSMutableString string];
    NSString *strTemp = [NSString string];
    
    // copy 出方法列表
    methodList = class_copyMethodList(cls, &outCount);
    
    // 遍历
    for (int i = 0; i < outCount; ++i) {
        tempMethod = methodList[i];
        strTemp = NSStringFromSelector(method_getName(tempMethod));
        [strResult appendFormat:@"\n%@", strTemp];
    }
    
    NSLog(@"%@", strResult);
}


@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 面试问题: iOS用什么方式实现对一个对象的KVO? 如何手动触发KVO? KVO简介 KVO就是键值观测。有时候...
    雪山飞狐_91ae阅读 10,062评论 10 36
  • 探索底层原理,积累从点滴做起。大家好,我是Mars。 往期回顾 iOS底层原理探索—OC对象的本质[https:/...
    劳模007_Mars阅读 5,042评论 4 9
  • 上篇文章我们通过一个简单的例子,讲述了KVO的基本使用情况,下面我们来继续深究KVO的本质是什么。 想要探究本质,...
    PerryMorning阅读 3,192评论 0 2
  • 1、如果你给一个Person实例添加KVO,那么这个实例的的isa指针指向的是派生出来了NSKVONotifica...
    我真的不是张亮阅读 3,218评论 0 0
  • 头发和指甲长得慢了、青春期推迟、免疫力低下……你知道这些可能跟什么相关吗?没错,这很有可能是因为缺乏蛋白质! 蛋白...
    纽扣妈咪阅读 3,180评论 0 0

友情链接更多精彩内容