iOS-KVC

343 阅读3分钟

定义

KVC(key-value coding,键值编码):可以允许开发者通过key名直接访问对象的属性,或者给对象的属性赋值,这样就可以在运行时动态地访问和修改对象的属性,而不是在编译时就确定

方法全览

在开发者手册中找到NSKeyValueCoding

KVC:一种可以通过名称或键间接的访问对象属性的机制

  • 取值方法

image.png

  • 设值方法

image.png

  • accessInstanceVariablesDirectly

该方法返回一个布尔值,该值指示在找不到属性的访问器方法时,键值编码方法是否应直接访问相应的实例变量

image.png

  • 属性验证

image.png

常用方法

key和keyPath

  • key:键
    • 只能接受当前类所具有的属性,不管是自己的,还是从父类继承过来的都可以接受
  • keyPath:键路径
    • 除了能接受当前类的属性,还能接受当前类的属性的属性,即可以接受关系链

取值方法

- (nullable id)valueForKey:(NSString *)key; //通过key来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过keyPath取值

基于getter取值的底层实现

img

设值方法

基于setter设值的底层实现

img

KVC内部在修改成员变量的同时是会主动调用willChangeValueForKey:didChangeValueForKey:,所以会触发KVO

注意⚠️:直接修改成员变量是不会触发KVO的,因为只是单纯的赋值,不会调用setter方法

属性验证

//key
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//keyPath
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;

该方法默认去探索类里面是否有一个这样的方法

  • 如果有,就调用这个方法来返回
  • 如果没有,就返回YES

处理异常

常见的异常有两种:传入了错误的key 和 传入了nil

  • 传入了错误的key

    可以通过重写下面两个方法,

    - (nullable id)valueForUndefinedKey:(NSString *)key;
    - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
    
  • 传入了nil

    如果不小心传入了nil,KVC会调用setNilValueForKey:方法,这个方法默认会抛出异常,所以一般我们就重写这个方法

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

处理非对象

  • valueForKey:总是返回一个id对象,如果原本的变量类型是值类型或者结构体,返回值会封装成NSNumber或者NSValue对象,这两个类会处理从数字,布尔值到指针和结构体任何类型,然后需要开发者手动转换成原来的类型
  • setValue:forKey::不会自动封装成对象,必须手动将值类型转换成NSNumber或者NSValue类型,才能传递过去

KVC与容器

引言

  • 对象的属性可以是一对一的,可以是一对多的
  • 一对多的属性要么是有序的(数组),要么是无序的(集合)

KVC与有序容器

取值方法:该方法返回一个可变有序数组

//key
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//keyPath
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;

底层实现原理

img

KVC与无序容器

取值方法:方法返回一个可变的无序数组

//key
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
//keyPath
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;

底层实现

img

KVC适用场景

动态取值设值

Model和字典的转换

在对象调用setValuesForKeysWithDictionary:方法时,可以传入一个包含keyvalue的字典进去,KVC可以将所有数据按照属性名和字典的key进行匹配,并将valueUser对象的属性赋值

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

KVC本质上是操作方法列表以及在内存中查找实例变量,因此我们可以利用这个特性来访问类的私有变量

这个操作对readonly的属性,@protected的成员变量,都可以正常访问

如果不想让外界访问类的成员变量,则可以将accessInstanceVariablesDirectly属性赋值为NO

修改一些控件的内部属性


参考博客:

iOS KVC全过程详解

iOS KVC底层原理、应用场景