美文网首页IOS底层
iOS 底层解析-----KVO与KVC原理

iOS 底层解析-----KVO与KVC原理

作者: Mr丨Yang | 来源:发表于2019-02-28 17:42 被阅读88次

    上文链接从isa指针看继承关系

    KVO 全称Key-Value Observing,俗称"键值监听",可以用于监听某个对象属性值的改变

    KVO 基本使用方法

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.person1 = [[MJPerson alloc] init];
        self.person1.age = 1;
        self.person1.height = 11;
        
        self.person2 = [[MJPerson alloc] init];
        self.person2.age = 2;
        self.person2.height = 22;
        
        // 给person1对象添加KVO监听
        NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
        [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
        [self.person1 addObserver:self forKeyPath:@"height" options:options context:@"456"];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        self.person1.age = 20;
        self.person2.age = 20;
        
        self.person1.height = 30;
        self.person2.height = 30;
    }
    
    // 当监听对象的属性值发生改变时,就会调用
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
    {
        NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
    }
    
    - (void)dealloc {
        [self.person1 removeObserver:self forKeyPath:@"age"];
        [self.person1 removeObserver:self forKeyPath:@"height"];
    }
    
    

    从上述代码可看出,alloc出来的person1 与 person2 实例对象,在点击屏幕的时候,只监测到了person1对象值的变化,没有监测到person2对象的变化?从代码的角度考虑是因为person2对象没有添加KVO,那么添加了KVO之后,person1实例对象在内存中发生了什么变换?

    先看person2实例对象的内存调用图


    未使用KVO监听.png

    person1实例对象使用了KVO 那么它的内存调用图如下

    使用KVO监听.png

    OC在运行时的时候自动生成了一个NSKVONotifying_MJPerson 类对象作为MJPerson类对象的子类对象,通过底层C _NSSetIntValueAndNotify方法 重写了setAge:方法,进而实现KVO的过程

    以下可理解为实现该过程的伪代码

    #import "MJPerson.h"
    
    @interface NSKVONotifying_MJPerson : MJPerson
    
    @end
    
    
    #import "NSKVONotifying_MJPerson.h"
    
    @implementation NSKVONotifying_MJPerson
    
    - (void)setAge:(int)age
    {
        _NSSetIntValueAndNotify();
    }
    
    // 伪代码
    void _NSSetIntValueAndNotify()
    {
        [self willChangeValueForKey:@"age"];
        [super setAge:age];
        [self didChangeValueForKey:@"age"];
    }
    
    - (void)didChangeValueForKey:(NSString *)key
    {
        // 通知监听器,某某属性值发生了改变
        [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
    }
    
    @end
    
    

    总结如图所示


    调用过程总结.png

    从上图可以看出来如果添加了KVO又不想修改属性值,那怎么主动调用监听方法呢,即可以调用以下两个方法主动去触发监听方法

    [self willChangeValueForKey:@"age"];
    
    [self didChangeValueForKey:@"age"];
    

    KVC 全称Key-Value Coding,俗称"键值编码",可以通过一个Key来访问某个属性

    KVC常用方法 (经常用到,用法不做过多解释)

    //赋值
    -(void)setValue:(id)value forKeyPath:(NSString *)keyPath; 
    -(void)setValue:(id)value forKey:(NSString *)key;
    
    //取值
    -(id)valueForKeyPath:(NSSting *)keyPath;
    -(id)valueForKey:(NSSting *)key;
    

    直接展示原理图

    赋值逻辑

    赋值.png

    取值逻辑

    取值.png

    注意:赋值,或 取值 都是有查找顺序的

    问题:KVC 修改属性会触发KVO么?
    会触发KVO的
    因为KVC内部会实现willChangeValueForKey: didChangeValueForKey: 方法 具体笔记不再论证

    下篇文章链接

    相关文章

      网友评论

        本文标题:iOS 底层解析-----KVO与KVC原理

        本文链接:https://www.haomeiwen.com/subject/pjqkuqtx.html