美文网首页
iOS-OC KVC KVO

iOS-OC KVC KVO

作者: 洧中苇_4187 | 来源:发表于2020-05-06 16:14 被阅读0次

    KVO的全称是Key-Value Observing,俗称“键值监听”

    作用:可以用于监听某个对象属性值的改变.
    被KVO监听的对象会有什么变化???
    创建一个类:

    @interface MJPerson : NSObject
    @property (nonatomic,strong)NSString *age;
    @end
    

    然后再viewController中

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.person = [MJPerson new];    
        [self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:@"123"];
        [self.person setValue:@"30" forKey:@"age"];
    }
    

    在给age赋值的时候会触发如下方法:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSString *oldValue = change[@"old"];
        NSString *newValue = change[@"new"];
    }
    

    在创建MJPerson这个类的时候,用KVO监听之后,runtime会在运行时动态的去创建一个叫NSKVONotifying_MJPerson的类,它继承自MJPerson类, 它的superClass指针指向MJPerson类对象,同样MJPerson对象的isa指针会指向这个类,
    如图:

    image.png

    如果我们尝试主动创建NSKVONotifying_MJPerson,看会有什么情况,结果会报错,告诉你这个类创建不了

    2020-05-06 14:54:20.088980+0800 KVO_test[48666:2446594] [general] KVO failed to allocate class pair for name NSKVONotifying_MJPerson, automatic key-value observing will not work for this class
    

    那么KVO的原理是什么???

    KVO是通过创建一个中间类,这个类继承自需要监听的类(MJPerson),在set方法之前调用- (void)willChangeValueForKey:(NSString *)key,在set方法之后调用- (void)didChangeValueForKey:(NSString *)key,并在这个方法里调用- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context,

    打印self.person的类对象(NSKVONotifying_MJPerson)的方法,类对象-元类有疑问的同学可以看我的上一篇 传送门
    通过object_getClass(self.person)可以拿到类对象(NSKVONotifying_MJPerson)

    Found 4 methods on 'NSKVONotifying_MJPerson'
        'NSKVONotifying_MJPerson' has method named 'setAge:' of encoding 'v24@0:8@16'
        'NSKVONotifying_MJPerson' has method named 'class' of encoding '#16@0:8'
        'NSKVONotifying_MJPerson' has method named 'dealloc' of encoding 'v16@0:8'
        'NSKVONotifying_MJPerson' has method named '_isKVOA' of encoding 'B16@0:8'
    

    它自己生成了上述四个方法:
    'setAge:' 这里面去调用父类的set方法,从而给_age赋值
    'class' 在你获取它的类的时候[MJPerson class]给你返回MJPerson,造成没有中间类的假象
    'dealloc' 监听之后的移除操作
    '_isKVOA' 标记是否有被监听

    问: 怎样主动触发监听方法

    答:主动调用- (void)willChangeValueForKey:(NSString *)key- (void)didChangeValueForKey:(NSString *)key

    问: NSKVONotifying_MJPerson它的isa指针指向哪里???
    (lldb) po object_getClass(self.person)
    NSKVONotifying_MJPerson
    
    (lldb) po object_getClass(object_getClass(self.person))
    NSKVONotifying_MJPerson
    
    (lldb) po object_getClass(object_getClass(object_getClass(self.person)))
    NSObject
    

    控制台的三次打印是这样,
    第一个打印是生成的监听MJPerson的类对象,
    第二次打印是生成NSKVONotifying_MJPerson的元类对象
    第三次打印是元类对象最终继承自NSObject

    KVC的全称是Key-Value Coding,俗称“键值编码”,

    作用:通过一个key来访问某个属性

    问: 通过KVC给某个属性赋值,会触发KVO吗,

    答:会会会,凡是通过set方法访问的值,都能触发KVO,前提是KVO必须监听这个属性

    KVC的查找机制就是:

    image.png
    第一步就是去查找setAge方法,然后_setAge,_age,_isAge,age,isAge,顺序找,当你MJPerson属性什么都没有,而你实现了如下方法,则KVC会调用它
    - (void)_setAge:(NSString *)age{
    //    _age = age;
    }
    

    注意:如果+ (BOOL)accessInstanceVariablesDirectly(能否直接访问成员变量 默认YES),返回NO,则找完setAge,_setAge就报错,setValue: forUndefinedKey

    取值原理和赋值原理基本一致.

    相关文章

      网友评论

          本文标题:iOS-OC KVC KVO

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