KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。
KVC在iOS中的定义
无论是Swift还是Objective-C,KVC的定义都是对NSObject的扩展来实现的(Objective-C中有个显式的NSKeyValueCoding类别名,而Swift没有,也不需要)。所以对于所有继承了NSObject的类型,也就是几乎所有的Objective-C对象都能使用KVC(一些纯Swift类和结构体是不支持KVC的),下面是KVC最为重要的四个方法
2.png 3.png//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
+ (BOOL)accessInstanceVariablesDirectly;
//KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。
- (BOOL)validateValue:(inoutid__nullable* __nonnull)ioValue forKey:(NSString*)inKey error:(outNSError**)outError;
//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。
- (NSMutableArray*)mutableArrayValueForKey:(NSString*)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。
- (nullableid)valueForUndefinedKey:(NSString*)key;
//和上一个方法一样,但这个方法是设值。
- (void)setValue:(nullableid)value forUndefinedKey:(NSString*)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString*)key;
//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
iOS成员变量、实例变量、属性区别?
1.png实例变量:由是实例创建的变量,是一种特殊的成员变量。
id 是一种特殊的class,是OC对象,
属性有默认的setter、getter,这是怎么来的?苹果早期编译器是GCC,后面变成了LLVM,LLVM如果发现一个实例变量,没有匹配到实例变量的属性的时候,它就会自动创建一个带下划线的变量名,同时会给你添加setter、getter方法,以前我们还需要一个函数@synthesize userName = _userName,它会自动生成setter、getter,它的作用是啥?第一步 自动帮你生成 setter、getter方法,第二部 指定属性对应的实例变量。
KVC的取值过程
取值过程的官方文档截图
取值1.png 取值2.png画的流程图
取值的流程图3.png代码示例:
代码1.png 代码2.png 代码3.png最后输出结果为 _name
这是为啥呢? 看流程图1 没有找到对应的 方法,然后LGPerson里面的accessInstanceVariablesDirectly返回的为yes,按照流程图的第4步 直接去查找_name,有直接赋值, 所以name的值为_name
数组get1.png 数组get2.png 数组get3.png 数组get4.png如果 LGPerson 没有写 array get相关 就会崩溃,按照 get流程的步骤2 实现了 objectInPensAtIndex 就会直接取值,不会崩溃了
set1.png set2.png set3.png set4.pngset取值的操作,按照取值步骤3,最终输出结果 如图set4.png
KVC的赋值过程
赋值过程的官方文档截图
putong1.png array1.png array2.png array3.png set1.png set2.png set3.png set4.png变量setter的流程
变量setter.png上面流程测试
accessNO-测试1.png accessNO-测试2.png accessNO-测试3.png accessNO-测试5.png accessYES-测试1.png accessYES-测试2.png accessYES-测试3.png数组赋值
当对象的属性是可变的容器时,对于有序的容器,可以用下面的方法:
array1.png array2.png代码测试
add1.png add2.png inser1.png inser2.png all1.png all2.png person1.png person2.png person3.png arrayset1.png arrayset2.png arrayset3.png arrayset4.pngNSMutableSet的set过程
set.png
可以看出 set 和 array 的取值方式 差不多,这里不做代码演示了。
KVC的正确性验证
check.png
这个方法的默认实现是去探索类里面是否有一个这样的方法:-(BOOL)validate<Key>:error:如果有这个方法,就调用这个方法来返回,没有的话就直接返回YES
vc.png person.png log.png自定义KVC逻辑
set值简单流程
set值简单流程.pngget值简单流程
get.png利用KVC处理异常
1.找不到key,setvalue:forkey 没这个key
异常1.png2.传值为nil
异常2.png 异常3.pngname属性是对象,所以赋值为nil不会崩溃,对象类型可以为nil;但是age是整数,整数的类型不会是nil,这么强行赋值就会抛出异常出现错误
异常4.png重写了这个方法就不会崩溃和出错了
异常5.pngKVC进阶用法
keyPath中的集合运算符的使用
①简单集合运算符
简单集合运算符共有
@avg 首先把集合中的每个对象都转换为double类型,然后计算其平均值,最后返回一个值为该平均值的NSNumber对象
@count 返回一个值为集合中对象总数的NSNumber对象
@max 使用compare:方法来确定最大值。所以为了让其正常工作,集合中所有的对象都必须支持和另一个对象的比较
@min 和@max一样,但是返回的是集合中的最小值。
@sum 首先把集合中的每个对象都转换为double类型,然后计算其总,最后返回一个值为这个总和的NSNumber对象
计算1.png 计算2.png对象操作符
NSArray*inventory = @[iPhone5, iPhone5, iPhone5, iPadMini, macBookPro, macBookPro];
@unionOfObjects/ @distinctUnionOfObjects: 返回一个由操作符右边的key path所指定的对象属性组成的数组。其中@distinctUnionOfObjects会对数组去重, 而@unionOfObjects不会。
[inventoryvalueForKeyPath:@"@unionOfObjects.name"];//"iPhone 5","iPhone 5","iPhone 5","iPad Mini","MacBook Pro","MacBook Pro"[inventoryvalueForKeyPath:@"@distinctUnionOfObjects.name"];//"iPhone 5","iPad Mini","MacBook Pro"
数组和集合操作符
数组和集合操作符跟对象操作符很相似,只不过它是在NSArray和NSSet所组成的集合中工作的。
@distinctUnionOfArrays/@unionOfArrays: 返回了一个数组,其中包含这个集合中每个数组对于这个操作符右面指定的key path进行操作之后的值。正如你期望的,distinct版本会移除重复的值。
@distinctUnionOfSets:和@distinctUnionOfArrays差不多, 但是它期望的是一个包含着NSSet对象的NSSet,并且会返回一个NSSet对象。因为集合不能包含重复的值,所以它只有distinct操作。
网友评论