zoukankan      html  css  js  c++  java
  • KVC/KVO 本质

    KVO 的实现原理

    1. KVO是关于runtime机制实现的

    2. 当某个类的对象属性第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制

    3. 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

    4. 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统就会偷偷讲isa指针指向动态生成的派生类,从而在给被监控属性复制是执行的是派生类的setter方法

    5. 键值观察通知依赖于NSObject的两个方法:willChangeValueForKey:和didChangeValueForKey:,在一个被观察属性发生改变之前,willChangeValueForkey:和didChangeValueForKey:;在一个被观察属性发生改变之前,willChangeValueForKey:一定会被调用,这就会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而observeValueForKey:ofObject:change:context:也会被调用

    举例伪代码_NSSet*ValueAndNotify
    
    - (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];
    }
    
    

    KVC的实现原理

    • KVC是Key Value Coding的简称。它是一种可以通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。KVC的方法定义在Foundation/NSKeyValueCoding中。

    KVC使用的基本方法:

    - (void)setValue:(nullableid)value forKey:(NSString*)key;//通过Key来设值
    - (void)setValue:(nullableid)value forKeyPath:(NSString*)keyPath;//通过KeyPath来设值
    - (nullableid)valueForKey:(NSString*)key;//直接通过Key来取值
    - (nullableid)valueForKeyPath:(NSString*)keyPath;//通过KeyPath来取值
    

    KVC 赋值 setValue:forKey:

    1. setValue:forKey:将键字符串key所对应的属性的值设置为value。(按照setKey:、_setKey:顺序查找方法)如果没有找到Set方法的话,将调用方法setValue:ForUndefinedKey:。并抛出异常 NSUnknowKeyException

    2. 若没有找到Set方法,会调用对象的类方法+ (BOOL)accessInstanceVariablesDirectly;此方法返回YES时(默认返回YES),会按照_key,_iskey,key,iskey的顺序搜索成员,然后赋值。

    3.  若都没找到成员变量,将调用方法setValue:ForUndefinedKey:。并抛出异常 NSUnknowKeyException

    KVC 取值值 valueForKey:

    1. 按先后顺序搜索getKey:、key、isKey、三个方法,若某一个方法被实现,取到的即是方法返回的值,后面的方法不再运行。如果是BOOL或者Int等值类型, 会将其包装成一个NSNumber对象。

    2. 若这三个方法都没有找到,则会调用+ (BOOL)accessInstanceVariablesDirectly方法判断是否允许取成员变量的值。若返回NO,直接调用- (nullable id)valueForUndefinedKey:(NSString *)key方法,并抛出异常 NSUnknowKeyException

    3. 若返回YES,会按先后顺序取_key、_isKey、 key、isKey成员变量的值。调用- (nullable id)valueForUndefinedKey:(NSString *)key方法。

    补充

    1. KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
    - - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
    
    1. KVC中的异常.获取值时找不到key- (nullable id)valueForUndefinedKey:(NSString *)key;

    2. 设值时找不到key- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

    3. 给不能设置nil的属性设置了nil。

    • 如果你在SetValue方法时面给Value传nil,则会调用这个方法
    • (void)setNilValueForKey:(NSString *)key;
  • 相关阅读:
    自定义View的ToolBar布局报错Error:(2) No resource identifier found for attribute 'context' in package 'c
    在学git之主分支 branch
    获取发布版SHA1
    关于开启线程与UI的操作
    播放音频和视频(VideoView控件)
    通知栏Notification的应用
    Android 真机调式 Installation failed with message 远程主机强迫关闭了一个现有的连接。. It is possible that this issue is resolved by uninstalling an existing version of the apk if it is present, and then re-installing. WA
    运行程序申请危险权限
    mysql乐观锁总结和实践
    Nginx配置文件nginx.conf中文详解
  • 原文地址:https://www.cnblogs.com/ShaoYinling/p/10238492.html
Copyright © 2011-2022 走看看