KVC
About Key-Value Coding
Key-value coding is a mechanism enabled by the NSKeyValueCoding informal protocol that objects adopt to provide indirect access to their properties. When an object is key-value coding compliant, its properties are addressable via string parameters through a concise, uniform messaging interface. This indirect access mechanism supplements the direct access afforded by instance variables and their associated accessor methods.
译:键值编码是一种由NSKeyValueCoding非正式协议所支持的机制,对象采用该协议来提供对其属性的间接访问。当一个对象的键值编码兼容时,它的属性通过一个简洁的、统一的消息传递接口通过字符串参数寻址。这种间接访问机制补充了实例变量及其相关访问方法所提供的直接访问。
You typically use accessor methods to gain access to an object’s properties. A get accessor (or getter) returns the value of a property. A set accessor (or setter) sets the value of a property. In Objective-C, you can also directly access a property’s underlying instance variable. Accessing an object property in any of these ways is straightforward, but requires calling on a property-specific method or variable name. As the list of properties grows or changes, so also must the code which accesses these properties. In contrast, a key-value coding compliant object provides a simple messaging interface that is consistent across all of its properties.
译:您通常使用访问器方法来访问对象的属性。获取访问器(或getter)返回属性的值。设置访问器(或setter)设置属性的值。在Objective-C中,还可以直接访问属性的底层实例变量。在任何一种方法中访问对象属性都很简单,但是需要调用特定于属性的方法或变量名。随着属性列表的增长或变化,访问这些属性的代码也必须如此。相反,一个键值编码兼容的对象提供了一个简单的消息接口,它在所有属性中都是一致的。
Key-value coding is a fundamental concept that underlies many other Cocoa technologies, such as key-value observing, Cocoa bindings, Core Data, and AppleScript-ability. Key-value coding can also help to simplify your code in some cases.
译:键值编码是基础概念,它支持许多其他的Cocoa技术,如键值观察、Cocoa绑定、Core Data和apples- ability。在某些情况下,键值编码还可以帮助简化代码。
KVC是Key Value Coding的缩写,即键值编码。在iOS的开发中,可以通过key名直接访问实例对象的属性,而不需要调用明确的存取方法。
也就是说我们可以在程序运行时动态地访问和修改对象的属性。KVC的定义都是对NSObject的扩展来实现的NSObject(NSKeyValueCoding),所以对于所有继承了NSObject的类型,都能使用KVC
看看苹果API给的解释
valueForKey:
- Search the instance for the first accessor method found with a name like
get
,,
is
, or_
, in that order. If found, invoke it and proceed to step 5 with the result. Otherwise proceed to the next step.- If no simple accessor method is found, search the instance for methods whose names match the patterns
countOf
andobjectIn
(corresponding to the primitive methods defined by theAtIndex: NSArray
class) and(corresponding to the
AtIndexes: [NSArray](https://developer.apple.com/library/archive/documentation/LegacyTechnologies/WebObjects/WebObjects_3.5/Reference/Frameworks/ObjC/Foundation/Classes/NSArrayClassCluster/Description.html#//apple_ref/occ/cl/NSArray)
methodobjectsAtIndexes:
).
If the first of these and at least one of the other two is found, create a collection proxy object that responds to allNSArray
methods and return that. Otherwise, proceed to step 3.
The proxy object subsequently converts anyNSArray
messages it receives to some combination ofcountOf
,objectIn
, andAtIndex: messages to the key-value coding compliant object that created it. If the original object also implements an optional method with a name like
AtIndexes: get
, the proxy object uses that as well, when appropriate. In effect, the proxy object working together with the key-value coding compliant object allows the underlying property to behave as if it were an:range: NSArray
, even if it is not.- If no simple accessor method or group of array access methods is found, look for a triple of methods named
countOf
,enumeratorOf
, andmemberOf
(corresponding to the primitive methods defined by the: [NSSet](https://developer.apple.com/library/archive/documentation/LegacyTechnologies/WebObjects/WebObjects_3.5/Reference/Frameworks/ObjC/Foundation/Classes/NSSetClassCluster/Description.html#//apple_ref/occ/cl/NSSet)
class).
If all three methods are found, create a collection proxy object that responds to allNSSet
methods and return that. Otherwise, proceed to step 4.
This proxy object subsequently converts anyNSSet
message it receives into some combination ofcountOf
,enumeratorOf
, andmemberOf
messages to the object that created it. In effect, the proxy object working together with the key-value coding compliant object allows the underlying property to behave as if it were an: NSSet
, even if it is not.- If no simple accessor method or group of collection access methods is found, and if the receiver's class method
[accessInstanceVariablesDirectly](https://developer.apple.com/library/archive/documentation/LegacyTechnologies/WebObjects/WebObjects_3.5/Reference/Frameworks/ObjC/EOF/EOControl/Classes/NSObjectAdditions/Description.html#//apple_ref/occ/clm/NSObject/accessInstanceVariablesDirectly)
returnsYES
, search for an instance variable named_
,_is
,, or
is
, in that order. If found, directly obtain the value of the instance variable and proceed to step 5. Otherwise, proceed to step 6.- If the retrieved property value is an object pointer, simply return the result.
If the value is a scalar type supported byNSNumber
, store it in anNSNumber
instance and return that.
If the result is a scalar type not supported by NSNumber, convert to anNSValue
object and return that.- If all else fails, invoke
[valueForUndefinedKey:](https://developer.apple.com/documentation/objectivec/nsobject/1413457-value)
. This raises an exception by default, but a subclass ofNSObject
may provide key-specific behavior.
- 按顺序搜索访问器方法get
/ /is /_ 。如果找到,调用该方法并且带着方法的调用结果调转到第5步执行;否则,继续下一步。 - 如果没有找到简单的访问方法,搜索其名称匹配某些模式的方法的实例。其中匹配模式包含countOf
,objectIn AtIndex:(对应于NSArray定义的基本方法),和 AtIndexs:(对应于NSArray的方法objectsAtIndexs:)一旦找到第一个和其他两个中的至少一个,则创建一个响应所以NSArray方法并返回该方法的集合代理对象。否则,执行第3步。
代理对象随后将任何NSArray接收到的一些组合的消息。实际上,与符合键值编码对象一起工作的代理对象允许底层属性的行为就像它是NSArray一样,即便它不是。 - 如果没有找到简单的访问器方法或数组访问方法组,则寻找三个方法countOf
/enumeratorOf /memberOf :,对应NSSet类的基本方法。 - 如果三个方法全找到了,则创建一个集合代理对象来响应所有的NSSet方法并返回。否则,执行第4步。如果上面的方法都没有找到,并且接受者的类方法accessInstanceVariablesDirectly返回YES(默认YES),则按序搜索以下实例变量:_
/_is / /is 。如果找到其中之一,直接获取实例变量的值并跳转到第5步;否则执行第6步。 - 如果检索到的属性值是对象指针,则只返回结果;如果值是受NSNumber支持的标量,则将其存储在NSNumber实例中并返回;如果结果是NSNumber不支持的标量,则转换成NSValue对象并返回
- 如果以上所有的尝试都失败了,则调用valueForUndefinedKey:,这个方法默认抛出异常,NSObject的子类可以重写来自定义行为。
setValue:
- Look for the first accessor named set
: or _set , in that order. If found, invoke it with the input value (or unwrapped value, as needed) and finish. - If no simple accessor is found, and if the class method accessInstanceVariablesDirectly returns YES, look for an instance variable with a name like _
, _is , , or is , in that order. If found, set the variable directly with the input value (or unwrapped value) and finish. - Upon finding no accessor or instance variable, invoke setValue:forUndefinedKey:. This raises an exception by default, but a subclass of NSObject may provide key-specific behavior.
- 按序搜索set
:或_set ,如果找到,则使用输入参数调用并结束。 - 如果没有找到简单的访问器方法,并且如果类方法accessInstanceVariablesDirectly返回YES(默认为YES),则按序搜索以下实例变量: _
/_is / /is ,如果找到了则直接进行赋值并结束。 - 以上方法皆失败则调用setValue:forUndefinedKey:,这个方法默认抛出异常,NSObject的子类可以自定义。
参考资料
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html