美文网首页
iOS学习笔记之KVC

iOS学习笔记之KVC

作者: Kity_Pei | 来源:发表于2019-08-09 15:52 被阅读0次

    前言

    这几天在面试过程中,常常被问到KVC,但是总觉得自己回答的不够全面细致,所以特此整理一份KVC的学习笔记。

    正文

    KVC介绍

    KVC全名是Key-value coding,键值编码。也就是说是在iOS开发过程中,允许开发者通过Key直接访问对象的属性,或者给对象的属性赋值。这也是由于ObjC的语言的特性(运行时)根本不必进行任何操作就可以对属性进行动态读写。

    KVC的操作方法由NSKeyValueCoding协议提供的,而NSObject就实现了这个协议,也就是说在ObjC中几乎所有的对象都支持KVC操作。

    常用到的方法:

    ///  动态读取
    - (nullable id)valueForKey:(NSString *)key;  // 通过Key取值
    - (nullable id)valueForKeyPath:(NSString *)keyPath;  // 通过KeyPath取值,通常使用场景都是对更深层的对象进行操作
    
    ///  动态设置
    - (void)setValue:(nullable id)value forKey:(NSString *)key;   // 通过Key设置值
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  // 通过KeyPath设置值,通常使用场景都是对更深层的对象进行操作
    

    KVC的实现原理

    设值

    设值过程

    1. 按照setKey:_setKey:顺序查找方法,如果找到了就执行;
    2. 如果未找到的话对应的set方法就会查看accessInstanceVariablesDirectly方法返回值,如果该方法返回值是true就会按照_key_isKeykey,isKey的顺序查找成员变量,如果找到了的话就会直接赋值,如果没有找到对应的成员变量的话,就会抛出NSUndefinedKeyException异常;
    3. 如果accessInstanceVariablesDirectly返回值是false的话,就会抛出NSUndefinedKeyException异常。

    设值总结

    KVC的设置值其实本质就是调用属性的setter方法;
    setter方法的优先级分别是setKey_setKeysetIsKey的优先级;
    accessInstanceVariablesDirectly方法默认值是true,会按照_key_isKeykey,isKey的顺序查找成员变量。

    取值原理

    取值过程

    1. 按照getKey,key,isKey的顺序查找getter方法,找到了直接调用(如果值是bool或者int等值类型的时候,会将其包装成NSNumber对象);
    2. 如果getter方法未找到,会继续查找countOfKeyobjectInKeyAtindex,KeyAtindexes格式的方法,如果countOfKey和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合的NSArray消息方法;
    3. 如果没有找到,会继续查找countOfKeyenumeratorOfKeymemberOfKey方法,如果这三个方法都找到了,那么就返回一个可以响应NSSet所有方法的代理集合;
    4. 如果没有找到,就会查看accessInstanceVariablesDirectly方法返回值,如果该方法返回值是true就会按照_key_isKeykey,isKey的顺讯查找成员变量,如果找到了的话就会直接赋值,如果没有找到对应的成员变量的话,就会抛出NSUndefinedKeyException异常;
    5. 如果accessInstanceVariablesDirectly返回值是false的话,就会抛出NSUndefinedKeyException异常。

    取值总结

    在取值过程中通过getKey:、key:、isKey:取到的值为直接返回的值,所以本质上是按先后顺序调用了这三个setter方法,如果没有,则会询问accessInstanceVariablesDirectly方法能否直接取成员变量,若返回true,则会按顺序取_key_isKeykeyisKey的值。

    KVC的应用场景

    KVC的主要应用场景:

    • 动态的取值和设值
    • 用KVC来访问和修改私有变量
    • Model和字典转换
    • 修改一些控件的内部属性

    动态的取值和设值

    利用KVC动态的取值和设值是最基本的用户。

    Person *p = [[Person alloc] init];
    [p setValue:@"Katy" forKey:@"name"]; // 设值
    [p setValue:@(27) forKey:@"age"];// 取值
    NSLog(@"%@的年龄是%@",[p valueForKey:@"name"],[p valueForKey:@"age"]);// 取值
    

    用KVC来访问和修改私有变量

    [textField setValue:[UIColor xxx] forKeyPath:@"_placeholderLabel.textColor"];
    

    不过iOS13一些私有的KVC会引发奔溃。这些好像跟系统版本无关,与Xcode版本有关,Xcode11编译会奔溃。
    所以通过KVC来访问和修改私有变量需慎重。

    Model和字典转换

    如果在做网络请求的时候解析数据不是使用第三方,而是自己写解析方法的话,这种就比较常见,就不再次赘述了。

    修改一些控件的内部属性

    一般会使用runtime结合KVC修改一些空间的内部属性。

    KVC常见异常

    NSUndefinedKeyException

    当根据KVC搜索规则进行搜索key或者keyPath的时候,没有找到对应的值,会调用对应的异常方法。如果是异常的默认实现时会抛出一个NSUndefinedKeyException的异常,应用程序会Crash

    解决方案是重写以下方法:

    - (id)valueForUndefinedKey:(NSString *)key;
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key;
    

    NSInvalidArgumentException

    当通过KVC给某个非对象的属性赋值为nil时,此时KVC会调用属性所属对象的- (void)setNilValueForKey:(NSString *)key;方法,并抛出NSInvalidArgumentException的异常,应用程序会Crash

    解决方案是重写以下方法:

    - (void)setNilValueForKey:(NSString *)key;
    

    相关文章

      网友评论

          本文标题:iOS学习笔记之KVC

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