KVC和KVO的一点研究

1 使用KVC 即 - (void)setValue:(nullable id)value forKey:(NSString *)key 给属性赋值的步骤

1.1 在实例所在类中查找与key对应的 asserror方法(setter方法)-set<Key>,如果没找到进入1.2步骤,如果找到接下来判断该方法的参数类型是否是对象类型,如果不是对象类型,那么先进行转换比如nsvalue ,nsnumber ,然后在调用相应的asserror方法。

1.2 如果没有找到对应的getter方法,如果类中的accessInstanceVariablesDirectly属性为NO那么进入1.3步骤,如果是YES那么查找该类中成员变量 _key _isKey key isKey ,如果被找到且实力变量是对象类型,那么value引用计数增加然后把值赋给对应的实例变量,如果实力变量不是对象类型那么要做和1.1步骤相同的事情即先转换然后把转换后的值赋给实例变量。

1.3 调用setValue:forUndefinedKey:该方法默认实现是抛出异常

例子:

@property(nonatomic)int age;
 [p1 setValue:@(123) forKey:@"age”];
[p1 setValue:@"123" forKey:@"age"];
该例子中两次使用kvc赋值结果一致。

 [p1 setValue:@"hello" forKey:@"age"];
    p1.age = @"hello”;
该例子中两种赋值结果不同之处在于使用kvc会先进行类型类型转换。

2 KVO实现原理就是在运行时创建了被观察者的一个Notifting_x的子类,然后修改被观察者对象的class指针指向该子类。

在该子类中重写了class方法。KVO某个属性的观察者会被触发的情况(直接或者使用KVC为实例变量赋值不会触发观察者因为此时没有调用setter方法)

2.1 属性的setter方法没有被重写的情况

2.1.1 调用set方法 即为属性赋值

2.1.2 使用kvc为属性赋值

2.1.3 willset didset调用

2.2 属性的setter方法被重新指定的情况(运行时子类不会重写该方法)

2.2.1 使用kvc为属性赋值

2.2.2 willset didset调用

猜你喜欢

转载自blog.csdn.net/qq_28117621/article/details/83994975
今日推荐