在iOS开发过程中,我们经常会听到或者用到KVO/KVC,但是对于什么是KVO和KVC,我们可能没有那么了解。下面先让我们来了解一下什么是KVC.
什么是KVC
在苹果的官方文档中是这样描述KVC的:它是一种通过字符串描述符而不是通过调用访问方法或者直接使用实例变量的非直接的访问对象属性的机制,说白了就是KVO是一种通过非常规方法访问成员变量或者属性的机制,这种非常规方式就是通过一个字符串标示符也就是所谓的key来访问属性或者成员变量。而这个key一般就是属性名或者实例变量名。
对于KVC的基本的方法都定义在NSKeyValueCoding的非正式协议中,并且NSObject默认实现了该协议。
KVC不仅支持对象类型,也支持数值类型和结构体。非对象类型的参数和返回类型会自动封装成NSValue或NSNumber类型。
KVO可以用来访问三种不同的对象值类型:属性、一对一关系、一对多关系
属性可以是诸如数值、字符串、bool类型等简单的值。也可以NSNumber或者NSColor这样的对象值。
在一对一关系里的对象可以拥有它自己的属性,这些属性可以在不改变对象的情况下被改变。像UIView的superView的属性,我们可以更改superView的属性,而不需要更改UIView。
一对多属性是一些相关对象的集合。通常用NSArray或者NSSet来存储这些集合。KVO也允许用户自定义集合类,但依然是像访问NSArray或者NSSet一样访问它们。
键和键路径
键是用来标识一个对象属性的字符串。一般情况下,键就是访问方法或者是对象的实例变量的名字。键必须是ASCII编码,以小写字母开头,并且不能包含空格。举几个键的例子:age、firstName、lastNmame等。
键路径是一串由点分隔的键组成的字符串,它是用来遍历一系列的对象属性的。第一个键的属性是跟接收者相关的,而每一个子系列是跟前一个属性相关的。比如键路径address.street,这个键路径会首先从接收者获得address属性,然后从address属性中获得street属性。
用KVC获得属性的值
方法valueForKey:会返回跟接收者相关的key的值。如果对于指定的key没有访问器或者实例变量,则给自己发送一个valueForUndefinedKey:消息,这个方法的默认实现是抛出一个NSUndefinedKeyException。子类可以重写这个方法。
同样的,valueForKeyPath:返回跟接收者相关的键路径的值。对于子系列中任何不遵循KVC的对象,都会收到一个valueForUndefineKey:消息。
dictionaryWithValuesForKeys:会检索数组中所有跟接收者相关的key的值。返回的NSDictionary中包含了数组中所有key的值。
注意:集合对象,比如NSArray、NSSet和NSDictionary中不能将nil作为一个值。相反的,应该用NSNull对象代替nil。NSNull是一个代表nil的对象属性。dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:方法的实现中,默认会在nil和NSNull之间进行转换。在你的对象中,不需要对nil做显示的测试。
用KVC设置属性的值
方法setValue:forKey:是将接收者中相关key的值设置成指定的值。在这个方法的实现中,会将NSValue的值转换成普通的数值然后赋给属性。
如果指定的key不存在,会给接收者发送一个setValue:forUndefinedKey:消息。这个方法的默认实现是抛出一个NSUndefinedKeyException异常,子类可以重写这个方法来自定义默认行为。
方法setValue:forKeyPath:的实现跟前面的一样,只不过它是用来处理键路径的。
setValuesForKeysWithDictionary:方法是用指定字典里的值来赋给接收者相关的属性。这个方法的默认实现是对每一对键-值都调用一次setValue:forKey:方法,并且自动将nil转成NSNull。
最后,你要关心的当尝试将一个nil值赋给一个非对象类型的时候该怎么办。这种情况下,接收者会发出一个setNilValueForKey:消息,这个方法的默认实现是抛出一个NSInvalidArgumentException。在你的应用中可以重写这个方法来定义一个默认值,然后用新的值触发setValue:forKey