美文网首页
KVC(Key-Value Coding)

KVC(Key-Value Coding)

作者: Kevin_ | 来源:发表于2021-06-07 15:32 被阅读0次

    一、KVC简介

    KVC:键值编码,使用字符串直接访问对象的属性

    常用方法

    @interface NSObject(NSKeyValueCoding)
     
    - (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
    - (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
    - (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值
     
    @end
    

    NSKeyValueCoding其他方法

    + (BOOL)accessInstanceVariablesDirectly;
    //默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
     
    - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
    //KVC提供属性值正确性�验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
     
    - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    //这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。
     
    - (nullable id)valueForUndefinedKey:(NSString *)key;
    //如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
     
    - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
    //和上一个方法一样,但这个方法是设值。
     
    - (void)setNilValueForKey:(NSString *)key;
    //如果你在SetValue方法时面给Value传nil,则会调用这个方法
     
    - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
    //输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
    

    二、实现原理

    setValue:forKey:原理

    1. 查找是否实现setter方法,如果有,优先调用setter方法完成赋值(注意:set后面的键的第一字字母必须是大写!!)
    2. 当没找到setter方法,调用accessInstanceVariablesDirectly询问;如果返回YES,顺序匹配变量名与_<key>_is<Key>,<key>,is<Key>,匹配到则设定其值,如果返回NO,结束查找,并调用 setValue:forUndefinedKey:报异常
    3. 如果既没有setter也没有实例变量时,调用 setValue:forUndefinedKey:
      setValue:forKey:原理

    valueForKey:的原理

    1. kvc取值按照 getKey、key、iskey、_key顺序查找方法
    2. 存在直接调用
    3. 没找到同样,先查看accessInstanceVariablesDirectly方法
    4. 如果可以访问会按照_key、_isKey、key、iskey的顺序查找成员变量
    5. 找到直接取值
    6. 如果所有情况都失败,则调用valueForUndefinedKey:方法并抛出NSUnkonwKeyException异常,这是默认行为,但是子类可以重写此方法。
    valueForKey:原理

    三、搜索规则

    NSMutableArray 、NSMutableSetNSMutableOrderedSet对应的搜索规则
    NSMutableSet为例说明:

    - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
    
    NSMutableSet原理
    1. 搜索addObject<Key>Object: , remove<Key>Object:或者 add<Key> , remove<Key>格式的方法
      如果至少找到一个insert方法和一个remove方法,那么同样返回一个可以响应NSMutableSet所有方法代理集合(类名是NSKeyValueFastMutableSet2),那么给这个代理集合发送NSMutableSet的方法,以addObject<Key>Object: , remove<Key>Object:或者 add<Key> , remove<Key>组合的形式调用。还有两个可选实现的接口:intersect<Key> , set<Key>:

    2. 如果receiverManagedObject,那么就不会继续搜索

    3. 如果上一步的方法没有找到,则搜索set<Key>: 格式的方法,如果找到,那么发送给代理集合的NSMutableSet最终都会调用set<Key>:方法。

    4. 如果上一步的方法还没有找到,再检查类方法+ (BOOL) accessInstanceVariablesDirectly,如果返回YES(默认行为),会按_<key>,<key>,的顺序搜索成员变量名,如果找到,那么发送的NSMutableSet消息方法直接交给这个成员变量处理。

    5. 如果还是找不到,则调用valueForUndefinedKey:

    四、适用场景

    1. 动态取值与设值
    • setValue:forKeyPath:valueForKeyPath:可以嵌套层级
    • setObject:forKey:ObjectForKey:中的key可以不为NSString
    • setObject:forKey:中的object不能为空,但是另外两者可以
    1. 字典转模型
    2. 访问或修改私有变量,iOS13之后苹果限制了此方法

    例如在.m中定义的私有成员变量和属性,都可以通过KVC的方式访问。
    这个操作对readonly的属性,@protected的成员变量,都可以正常访问。如果不想让外界访问类的成员变量,则可以将accessInstanceVariablesDirectly属性赋值为NO

    1. 修改一些控件的内部属性

    众所周知很多UI控件都由很多内部UI控件组合而成的,但是Apple度没有提供这访问这些控件的API,这样我们就无法正常地访问和修改这些控件的样式。而KVC在大多数情况可下可以解决这个问题。

    五、KVC异常处理

    1. key或者keyPath发生错误

    当根据KVC搜索规则,没有搜索到对应的key或者keyPath,则会调用对应的异常方法。异常方法的默认实现,在异常发生时会抛出一个NSUndefinedKeyException的异常,并且应用程序Crash
    我们可以重写下面两个方法(这种方法只能运用在自己类的对象中):

    - (nullable id)valueForUndefinedKey:(NSString *)key;
    - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
    
    
    1. 传参为nil

    通常情况下,KVC不允许你要在调用setValue:属性值 forKey:(或者keyPath)时对非对象传递一个nil的值;如果你不小心传了,KVC会调用setNilValueForKey:方法。这个方法默认是抛出异常,所以一般而言最好还是重写这个方法。

    我们可以重写这个方法:

    -(void)setNilValueForKey:(NSString *)key{
        NSLog(@"不能将%@设成nil",key);
    }
    
    1. 使用swizzling

    相关文章

      网友评论

          本文标题:KVC(Key-Value Coding)

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