KVC从头文件注释说起
一、简介
关于KVC(键值编码)的文章可以说,已经烂大街了,烂烂烂大街了。而且,这个东西,面试的时候,超级喜欢问。我也不知道为什么,可能是我技术太烂。但我猜想,也许是因为关于这个东西的文档太少太少吧。
官方文档说,键值编码是一个非正式的协议。什么是非正式的协议,在我看来,就是不用Protocol这种东西明确定义的,事实也确实是这样(系统是以NSObject的NSKeyValueCoding分类的方式提供的)。KVC用来干什么的呢,我的理解是,他是一个除了accessor(访问器)和公有instance variable(实例变量)之外,一个统一的访问对象属性的机制。KVO与KVC有非常密切的联系,KVC提供了KVO的一些基础设施,KVO我们之后再一起玩耍。
接下来,进入正题,我们来一起阅读头文件。
二、阅读头文件
/* The exception that is thrown when a key value coding operation fails. The exception's user info dictionary will contain at least two entries:
- @"NSTargetObjectUserInfoKey": the receiver of the failed KVC message.
- @"NSUnknownUserInfoKey": the key that was used in the failed KVC message.
The actual value of this constant string is "NSUnknownKeyException," to match the exceptions that are thrown by KVC methods that were deprecated in Mac OS 10.3.
*/
FOUNDATION_EXPORT NSExceptionName const NSUndefinedKeyException;
文档翻译:
这是键值编码操作失败时抛出的异常。这个异常的用户信息字典包括至少两个实体:
- @"NSTargetObjectUserInfoKey"
:这是失败的键值编码消息的接收者。
- @"NSUnknownUserInfoKey"
:这是失败的键值编码消息使用的键。
这个常量字符串的真实的值是"NSUnknownKeyException"
,为了跟弃用的MacOS10.3键值编码方法抛出的异常相匹配。
typedef NSString * NSKeyValueOperator NS_STRING_ENUM;
/* Strings for the names of array operators supported by key-value coding. Only these string declarations are new in Mac OS 10.4. The actual support for array operators appeared in Mac OS 10.3. The values of these do not include "@" prefixes.
*/
FOUNDATION_EXPORT NSKeyValueOperator const NSAverageKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSCountKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSDistinctUnionOfArraysKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSDistinctUnionOfObjectsKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSDistinctUnionOfSetsKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSMaximumKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSMinimumKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSSumKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSUnionOfArraysKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSUnionOfObjectsKeyValueOperator;
FOUNDATION_EXPORT NSKeyValueOperator const NSUnionOfSetsKeyValueOperator;
文档翻译:
这些字符串用来表示键值编码支持的数组操作符的名称。只有这些字符串是在MacOS 10.4中新声明的。真正的对数组操作符的支持是在MacOS 10.3中出现的。这些值都是不包括键值编码的数组操作符前缀“@”的。
@interface NSObject(NSKeyValueCoding)
/* Return YES if -valueForKey:, -setValue:forKey:, -mutableArrayValueForKey:, -storedValueForKey:, -takeStoredValue:forKey:, and -takeValue:forKey: may directly manipulate instance variables when sent to instances of the receiving class, NO otherwise. The default implementation of this property returns YES.
*/
@property (class, readonly) BOOL accessInstanceVariablesDirectly;
文档翻译:
此属性返回YES
,如果需要这个类的对象的-valueForKey:
, -setValue:forKey:
, -mutableArrayValueForKey:
, -storedValueForKey:
, -takeStoredValue:forKey:
, 和 -takeValue:forKey:
方法可以操作实例变量的话。否则,返回NO
。默认实现此属性的值返回YES
。
/* Given a key that identifies an attribute or to-one relationship, return the attribute value or the related object. Given a key that identifies a to-many relationship, return an immutable array or an immutable set that contains all of the related objects.
The default implementation of this method does the following:
1. Searches the class of the receiver for an accessor method whose name matches the pattern -get<Key>, -<key>, or -is<Key>, in that order. If such a method is found it is invoked. If the type of the method's result is an object pointer type the result is simply returned. If the type of the result is one of the scalar types supported by NSNumber conversion is done and an NSNumber is returned. Otherwise, conversion is done and an NSValue is returned (new in Mac OS 10.5: results of arbitrary type are converted to NSValues, not just NSPoint, NRange, NSRect, and NSSize).
2 (introduced in Mac OS 10.7). Otherwise (no simple accessor method is found), searches the class of the receiver for methods whose names match the patterns -countOf<Key> and -indexIn<Key>OfObject: and -objectIn<Key>AtIndex: (corresponding to the primitive methods defined by the NSOrderedSet class) and also -<key>AtIndexes: (corresponding to -[NSOrderedSet objectsAtIndexes:]). If a count method and an indexOf method and at least one of the other two possible methods are found, a collection proxy object that responds to all NSOrderedSet methods is returned. Each NSOrderedSet message sent to the collection proxy object will result in some combination of -countOf<Key>, -indexIn<Key>OfObject:, -objectIn<Key>AtIndex:, and -<key>AtIndexes: messages being sent to the original receiver of -valueForKey:. If the class of the receiver also implements an optional method whose name matches the pattern -get<Key>:range: that method will be used when appropriate for best performance.
3. Otherwise (no simple accessor method or set of ordered set access methods is found), searches the class of the receiver for methods whose names match the patterns -countOf<Key> and -objectIn<Key>AtIndex: (corresponding to the primitive methods defined by the NSArray class) and (introduced in Mac OS 10.4) also -<key>AtIndexes: (corresponding to -[NSArray objectsAtIndexes:]). If a count method and at least one of the other two possible methods are found, a collection proxy object that responds to all NSArray methods is returned. Each NSArray message sent to the collection proxy object will result in some combination of -countOf<Key>, -objectIn<Key>AtIndex:, and -<key>AtIndexes: messages being sent to the original receiver of -valueForKey:. If the class of the receiver also implements an optional method whose name matches the pattern -get<Key>:range: that method will be used when appropriate for best performance.
4 (introduced in Mac OS 10.4). Otherwise (no simple accessor method or set of ordered set or array access methods is found), searches the class of the receiver for a threesome of methods whose names match the patterns -countOf<Key>, -enumeratorOf<Key>, and -memberOf<Key>: (corresponding to the primitive methods defined by the NSSet class). If all three such methods are found a collection proxy object that responds to all NSSet methods is returned. Each NSSet message sent to the collection proxy object will result in some combination of -countOf<Key>, -enumeratorOf<Key>, and -memberOf<Key>: messages being sent to the original receiver of -valueForKey:.
5. Otherwise (no simple accessor method or set of collection access methods is found), if the receiver's class' +accessInstanceVariablesDirectly property returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key>, _is<Key>, <key>, or is<Key>, in that order. If such an instance variable is found, the value of the instance variable in the receiver is returned, with the same sort of conversion to NSNumber or NSValue as in step 1.
6. Otherwise (no simple accessor method, set of collection access methods, or instance variable is found), invokes -valueForUndefinedKey: and returns the result. The default implementation of -valueForUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.
Compatibility notes:
- For backward binary compatibility, an accessor method whose name matches the pattern -_get<Key>, or -_<key> is searched for between steps 1 and 3. If such a method is found it is invoked, with the same sort of conversion to NSNumber or NSValue as in step 1. KVC accessor methods whose names start with underscores were deprecated as of Mac OS 10.3 though.
- The behavior described in step 5 is a change from Mac OS 10.2, in which the instance variable search order was <key>, _<key>.
- For backward binary compatibility, -handleQueryWithUnboundKey: will be invoked instead of -valueForUndefinedKey: in step 6, if the implementation of -handleQueryWithUnboundKey: in the receiver's class is not NSObject's.
*/
- (nullable id)valueForKey:(NSString *)key;
文档翻译:
当传递的键定义的是一个属性或者一对一关系(通常是指一个不可变对象,或者是基础数据类型的属性或者实例变量),返回这个属性的值或者关联的对象。当传递的键是一对多关系(通常是指一个可变的集合类型的属性或实例变量),返回一个不可变的包含所有关联对象的数组或者集对象。
此方法的默认实现如下:
- 搜索消息接收者的类,依次查找名称匹配
-get<Key>
,-<key>
, 或-is<Key>
模式的访问器方法。如果找到,就调用这个方法。如果方法返回结果的类型是对象指针类型,那么就直接返回;如果方法返回的结果是NSNumber
可以支持的基础数据类型,那么自动类型转换,并返回一个NSNumber
对象。否则,自动转换成NSValue
类型并返回(在Mac OS 10.5环境下:任意类型的返回值将被转换成NSValues返回,不仅限于NSPoint
,NRange
,NSRect
, 和NSSize
)。 - (Mac OS 10.7开始引入)否则(没有简单的访问器方法被找到),搜索消息接收者的类,查找名称匹配
-countOf<Key>
,-indexIn<Key>OfObject:
,和-objectIn<Key>AtIndex:
(对应于NSOrderedSet类定义的基础方法)以及-<key>AtIndexes:
(对应-[NSOrderedSet objectsAtIndexes:]
)模式的方法。如果一个count方法和一个indexOf方法,以及至少其它两个可能的方法中的一个被找到,返回一个能够响应所有NSOrderedSet
方法的集合代理对象。每一条发送给集合代理对象的NSOrderedSet
消息,将会导致一系列的-countOf<Key>
,-indexIn<Key>OfObject:
,-objectIn<Key>AtIndex:
, 和-<key>AtIndexes:
消息组合被转发给-valueForKey:
消息的原始接收者。如果消息接收者的类还实现了名称匹配-get<Key>:range:
模式的可选方法,那么这个方法将会在适当的时候为最佳性能而调用。 - 否则(简单访问器方法,或者一组有序集合的写访问器方法都没找到),搜索消息接收者的类,查找名称匹配
-countOf<Key>
和-objectIn<Key>AtIndex:
(对应NSArray
类定义的基础方法)以及(Mac OS 10.4 开始引入)-<key>AtIndexes:
(对应-[NSArray objectsAtIndexes:]
)模式的方法。如果一个count方法和至少其它两个可能的方法中的一个被找到,返回一个能够响应所有NSArray
方法的集合代理。每一条发送给集合代理对象的NSArray
消息,将会导致一系列的-countOf<Key>
,-objectIn<Key>AtIndex:
, 和-<key>AtIndexes:
消息组合被转发给-valueForKey:
消息的原始接收者。如果消息接收者的类还实现了名称匹配-get<Key>:range:
模式的可选方法,那么这个方法将会在适当的时候为最佳性能而调用。 - (从Mac OS 10.4开始引入)否则(没有简单访问器方法、一组有序集合的写访问器方法,或者数组的访问器方法都没找到),搜索消息接收者的类,查找三个一组的名称匹配
-countOf<Key>
,-enumeratorOf<Key>
, 和-memberOf<Key>:
(对应NSSet
定义的基础方法)模式的方法。如果这三个方法都找到,返回一个响应所有NSSet
方法的集合代理对象。每一条发送给集合代理对象的NSSet
消息,将会导致一系列的-countOf<Key>
,-enumeratorOf<Key>
, 和-memberOf<Key>:
消息组合被转发给-valueForKey:
消息的原始接收者。 - 否则(没有简单访问器方法,或者一组集合访问器方法被找到),如果消息接收者的类的
+accessInstanceVariablesDirectly
属性返回YES,搜索消息接收者的类,顺序查找名称匹配_<key>
,_is<Key>
,<key>
, 或is<Key>
的实例变量。如果这样的实例变量被找到,消息接收者的实例变量值被返回,遵循与步骤1相同的NSNumber
或NSvalue
类型转换规则。 - 否则(没有简单访问器方法,一组集合访问器方法,或者实例变量被找到),调用-
valueForUndefinedKey:
方法并返回结果。-valueForUndefinedKey:
方法的默认实现抛出一个异常,但你可以在你的应用中重写这个方法。
兼容性注释:
- 为了后向的二进制兼容,在步骤1和3之间,还会搜索访问器方法名称匹配
-_get<Key>
, 或-_<key>
模式的方法。如果这样的方法被查找,就调用,遵循与步骤1相同的类型转换规则。尽管以下划线开头的键值编码访问器方法已经在Mac OS 10.3中被弃用。 - 步骤5中描述的行为从Mac OS 10.2开始有了改变,原来的查找实例变量查找顺序是
<key>
,_<key>
。 - 为了后向的二进制兼容,如果消息接收者的类的
-handleQueryWithUnboundKey:
方法实现不是NSObjec
t的(我个人理解为,不是继承自NSObject
,而是重写了这个方法),步骤6中,将会调用-handleQueryWithUnboundKey:
方法,来取代valueForUndefinedKey:
。
/* Given a value and a key that identifies an attribute, set the value of the attribute. Given an object and a key that identifies a to-one relationship, relate the object to the receiver, unrelating the previously related object if there was one. Given a collection object and a key that identifies a to-many relationship, relate the objects contained in the collection to the receiver, unrelating previously related objects if there were any.
The default implementation of this method does the following:
1. Searches the class of the receiver for an accessor method whose name matches the pattern -set<Key>:. If such a method is found the type of its parameter is checked. If the parameter type is not an object pointer type but the value is nil -setNilValueForKey: is invoked. The default implementation of -setNilValueForKey: raises an NSInvalidArgumentException, but you can override it in your application. Otherwise, if the type of the method's parameter is an object pointer type the method is simply invoked with the value as the argument. If the type of the method's parameter is some other type the inverse of the NSNumber/NSValue conversion done by -valueForKey: is performed before the method is invoked.
2. Otherwise (no accessor method is found), if the receiver's class' +accessInstanceVariablesDirectly property returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key>, _is<Key>, <key>, or is<Key>, in that order. If such an instance variable is found and its type is an object pointer type the value is retained and the result is set in the instance variable, after the instance variable's old value is first released. If the instance variable's type is some other type its value is set after the same sort of conversion from NSNumber or NSValue as in step 1.
3. Otherwise (no accessor method or instance variable is found), invokes -setValue:forUndefinedKey:. The default implementation of -setValue:forUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.
Compatibility notes:
- For backward binary compatibility with -takeValue:forKey:'s behavior, a method whose name matches the pattern -_set<Key>: is also recognized in step 1. KVC accessor methods whose names start with underscores were deprecated as of Mac OS 10.3 though.
- For backward binary compatibility, -unableToSetNilForKey: will be invoked instead of -setNilValueForKey: in step 1, if the implementation of -unableToSetNilForKey: in the receiver's class is not NSObject's.
- The behavior described in step 2 is different from -takeValue:forKey:'s, in which the instance variable search order is <key>, _<key>.
- For backward binary compatibility with -takeValue:forKey:'s behavior, -handleTakeValue:forUnboundKey: will be invoked instead of -setValue:forUndefinedKey: in step 3, if the implementation of -handleTakeValue:forUnboundKey: in the receiver's class is not NSObject's.
*/
- (void)setValue:(nullable id)value forKey:(NSString *)key;
文档翻译:
接受一个值和一个定义属性的键,将这个值设置为属性的值。接受一个对象和一个定义一对一关系的键,将会关联这个对象和消息接收者,如果已经有关联对象,则解除原关联对象的关联关系。接受一个集合对象和一个定义一对多关系的键,将会关联集合包含的对象和消息接收者,如果已有关联对象,则解除原关联对象的关联关系。
此方法的默认实现是:
- 搜索消息接收者的类,查找名称匹配
set<Key>:
模式的访问器方法。如果找到访问器方法,会执行参数类型检查。如果参数类型不是一个对象的指针,而是nil
,则-setNilValueForKey:
被调用。-setNilValueForKey:
的默认实现会抛出一个NSInvalidArgumentException
异常,但你可以在应用程序中重写此方法。或者,如果参数的类型是对象指针,则方法会以此参数正常调用。 - 否则(没有找到对应的访问器方法),如果接收者的类
+accessInstanceVariablesDirectly
属性值返回YES,按顺序搜索类中包含名称匹配_<key>
,_is<Key>
,<key>
, 或is<Key>
模式的实例变量。如果找到这样的实例变量,并且实例变量的类型是对象指针类型,首先释放掉旧值对象,然后给这个新值对象的引用计数加一,最后把它赋值给实例变量。如果实例变量的类型是其它类型,首先执行类似Number
或NSValue
的类型转换,然后再把值赋值给实例变量。 - 否则(没有找到对应的访问器方法或实例变量),则调用-
setValue:forUndefinedKey:
。-setValue:forUndefinedKey:
方法的默认实现会抛出一个NSUndefinedKeyException
异常,但你可以在应用程序中重写此方法。
兼容性注释:
- 为了后向的二进制兼容
-takeValue:forKey:
方法的行为,在步骤1中,名称匹配-_set<Key>:
模式的方法也会被识别,尽管方法名以下划线开头的KVC访问器方法在Mac OS 10.3已经被弃用了。 - 为了后向的二进制兼容,在步骤1中,如果消息接收者
-unableToSetNilForKey:
方法的实现不是NSObject
的实现(个人理解为,重写了这个方法)。-unableToSetNilForKey:
将取代-setNilValueForKey:
被调用。 - 步骤2所描述的行为与
-takeValue:forKey:
方法搜索实例变量的顺序<key>
,_<key>
不同了。 - 为了后向的二进制兼容
-takeValue:forKey:
方法的行为,如果消息接收者-handleTakeValue:forUnboundKey:
方法的实现不是NSObject
的实现(个人理解为,重写了这个方法),在步骤3中
-handleTakeValue:forUnboundKey:
将取代-setValue:forUndefinedKey:
方法被调用。
/* Given a pointer to a value pointer, a key that identifies an attribute or to-one relationship, and a pointer to an NSError pointer, return a value that is suitable for use in subsequent -setValue:forKey: messages sent to the same receiver. If no validation is necessary, return YES without altering *ioValue or *outError. If validation is necessary and possible, return YES after setting *ioValue to an object that is the validated version of the original value, but without altering *outError. If validation is necessary but not possible, return NO after setting *outError to an NSError that encapsulates the reason that validation was not possible, but without altering *ioValue. The sender of the message is never given responsibility for releasing ioValue or outError.
The default implementation of this method searches the class of the receiver for a validator method whose name matches the pattern -validate<Key>:error:. If such a method is found it is invoked and the result is returned. If no such method is found, YES is returned.
*/
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
/* Given a key that identifies an _ordered_ to-many relationship, return a mutable array that provides read-write access to the related objects. Objects added to the mutable array will become related to the receiver, and objects removed from the mutable array will become unrelated.
The default implementation of this method recognizes the same simple accessor methods and array accessor methods as -valueForKey:'s, and follows the same direct instance variable access policies, but always returns a mutable collection proxy object instead of the immutable collection that -valueForKey: would return. It also:
1. Searches the class of the receiver for methods whose names match the patterns -insertObject:in<Key>AtIndex: and -removeObjectFrom<Key>AtIndex: (corresponding to the two most primitive methods defined by the NSMutableArray class), and (introduced in Mac OS 10.4) also -insert<Key>:atIndexes: and -remove<Key>AtIndexes: (corresponding to -[NSMutableArray insertObjects:atIndexes:] and -[NSMutableArray removeObjectsAtIndexes:). If at least one insertion method and at least one removal method are found each NSMutableArray message sent to the collection proxy object will result in some combination of -insertObject:in<Key>AtIndex:, -removeObjectFrom<Key>AtIndex:, -insert<Key>:atIndexes:, and -remove<Key>AtIndexes: messages being sent to the original receiver of -mutableArrayValueForKey:. If the class of the receiver also implements an optional method whose name matches the pattern -replaceObjectIn<Key>AtIndex:withObject: or (introduced in Mac OS 10.4) -replace<Key>AtIndexes:with<Key>: that method will be used when appropriate for best performance.
2. Otherwise (no set of array mutation methods is found), searches the class of the receiver for an accessor method whose name matches the pattern -set<Key>:. If such a method is found each NSMutableArray message sent to the collection proxy object will result in a -set<Key>: message being sent to the original receiver of -mutableArrayValueForKey:.
3. Otherwise (no set of array mutation methods or simple accessor method is found), if the receiver's class' +accessInstanceVariablesDirectly property returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key> or <key>, in that order. If such an instance variable is found, each NSMutableArray message sent to the collection proxy object will be forwarded to the instance variable's value, which therefore must typically be an instance of NSMutableArray or a subclass of NSMutableArray.
4. Otherwise (no set of array mutation methods, simple accessor method, or instance variable is found), returns a mutable collection proxy object anyway. Each NSMutableArray message sent to the collection proxy object will result in a -setValue:forUndefinedKey: message being sent to the original receiver of -mutableArrayValueForKey:. The default implementation of -setValue:forUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.
Performance note: the repetitive -set<Key>: messages implied by step 2's description are a potential performance problem. For better performance implement insertion and removal methods that fulfill the requirements for step 1 in your KVC-compliant class. For best performance implement a replacement method too.
*/
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
/* Given a key that identifies an _ordered_ and uniquing to-many relationship, return a mutable ordered set that provides read-write access to the related objects. Objects added to the mutable ordered set will become related to the receiver, and objects removed from the mutable ordered set will become unrelated.
The default implementation of this method recognizes the same simple accessor methods and ordered set accessor methods as -valueForKey:'s, and follows the same direct instance variable access policies, but always returns a mutable collection proxy object instead of the immutable collection that -valueForKey: would return. It also:
1. Searches the class of the receiver for methods whose names match the patterns -insertObject:in<Key>AtIndex: and -removeObjectFrom<Key>AtIndex: (corresponding to the two most primitive methods defined by the NSMutableOrderedSet class), and also -insert<Key>:atIndexes: and -remove<Key>AtIndexes: (corresponding to -[NSMutableOrderedSet insertObjects:atIndexes:] and -[NSMutableOrderedSet removeObjectsAtIndexes:). If at least one insertion method and at least one removal method are found each NSMutableOrderedSet message sent to the collection proxy object will result in some combination of -insertObject:in<Key>AtIndex:, -removeObjectFrom<Key>AtIndex:, -insert<Key>:atIndexes:, and -remove<Key>AtIndexes: messages being sent to the original receiver of -mutableOrderedSetValueForKey:. If the class of the receiver also implements an optional method whose name matches the pattern -replaceObjectIn<Key>AtIndex:withObject: or -replace<Key>AtIndexes:with<Key>: that method will be used when appropriate for best performance.
2. Otherwise (no set of ordered set mutation methods is found), searches the class of the receiver for an accessor method whose name matches the pattern -set<Key>:. If such a method is found each NSMutableOrderedSet message sent to the collection proxy object will result in a -set<Key>: message being sent to the original receiver of -mutableOrderedSetValueForKey:.
3. Otherwise (no set of ordered set mutation methods or simple accessor method is found), if the receiver's class' +accessInstanceVariablesDirectly property returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key> or <key>, in that order. If such an instance variable is found, each NSMutableOrderedSet message sent to the collection proxy object will be forwarded to the instance variable's value, which therefore must typically be an instance of NSMutableOrderedSet or a subclass of NSMutableOrderedSet.
4. Otherwise (no set of ordered set mutation methods, simple accessor method, or instance variable is found), returns a mutable collection proxy object anyway. Each NSMutableOrderedSet message sent to the collection proxy object will result in a -setValue:forUndefinedKey: message being sent to the original receiver of -mutableOrderedSetValueForKey:. The default implementation of -setValue:forUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.
Performance note: the repetitive -set<Key>: messages implied by step 2's description are a potential performance problem. For better performance implement insertion and removal methods that fulfill the requirements for step 1 in your KVC-compliant class. For best performance implement a replacement method too.
*/
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/* Given a key that identifies an _unordered_ and uniquing to-many relationship, return a mutable set that provides read-write access to the related objects. Objects added to the mutable set will become related to the receiver, and objects removed from the mutable set will become unrelated.
The default implementation of this method recognizes the same simple accessor methods and set accessor methods as -valueForKey:'s, and follows the same direct instance variable access policies, but always returns a mutable collection proxy object instead of the immutable collection that -valueForKey: would return. It also:
1. Searches the class of the receiver for methods whose names match the patterns -add<Key>Object: and -remove<Key>Object: (corresponding to the two primitive methods defined by the NSMutableSet class) and also -add<Key>: and -remove<Key>: (corresponding to -[NSMutableSet unionSet:] and -[NSMutableSet minusSet:]). If at least one addition method and at least one removal method are found each NSMutableSet message sent to the collection proxy object will result in some combination of -add<Key>Object:, -remove<Key>Object:, -add<Key>:, and -remove<Key>: messages being sent to the original receiver of -mutableSetValueForKey:. If the class of the receiver also implements an optional method whose name matches the pattern -intersect<Key>: or -set<Key>: that method will be used when appropriate for best performance.
2. Otherwise (no set of set mutation methods is found), searches the class of the receiver for an accessor method whose name matches the pattern -set<Key>:. If such a method is found each NSMutableSet message sent to the collection proxy object will result in a -set<Key>: message being sent to the original receiver of -mutableSetValueForKey:.
3. Otherwise (no set of set mutation methods or simple accessor method is found), if the receiver's class' +accessInstanceVariablesDirectly property returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key> or <key>, in that order. If such an instance variable is found, each NSMutableSet message sent to the collection proxy object will be forwarded to the instance variable's value, which therefore must typically be an instance of NSMutableSet or a subclass of NSMutableSet.
4. Otherwise (no set of set mutation methods, simple accessor method, or instance variable is found), returns a mutable collection proxy object anyway. Each NSMutableSet message sent to the collection proxy object will result in a -setValue:forUndefinedKey: message being sent to the original receiver of -mutableSetValueForKey:. The default implementation of -setValue:forUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.
Performance note: the repetitive -set<Key>: messages implied by step 2's description are a potential performance problem. For better performance implement methods that fulfill the requirements for step 1 in your KVC-compliant class.
*/
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
/* Key-path-taking variants of like-named methods. The default implementation of each parses the key path enough to determine whether or not it has more than one component (key path components are separated by periods). If so, -valueForKey: is invoked with the first key path component as the argument, and the method being invoked is invoked recursively on the result, with the remainder of the key path passed as an argument. If not, the like-named non-key-path-taking method is invoked.
*/
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
/* Given that an invocation of -valueForKey: would be unable to get a keyed value using its default access mechanism, return the keyed value using some other mechanism. The default implementation of this method raises an NSUndefinedKeyException. You can override it to handle properties that are dynamically defined at run-time.
*/
- (nullable id)valueForUndefinedKey:(NSString *)key;
/* Given that an invocation of -setValue:forKey: would be unable to set the keyed value using its default mechanism, set the keyed value using some other mechanism. The default implementation of this method raises an NSUndefinedKeyException. You can override it to handle properties that are dynamically defined at run-time.
*/
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
/* Given that an invocation of -setValue:forKey: would be unable to set the keyed value because the type of the parameter of the corresponding accessor method is an NSNumber scalar type or NSValue structure type but the value is nil, set the keyed value using some other mechanism. The default implementation of this method raises an NSInvalidArgumentException. You can override it to map nil values to something meaningful in the context of your application.
*/
- (void)setNilValueForKey:(NSString *)key;
/* Given an array of keys, return a dictionary containing the keyed attribute values, to-one-related objects, and/or collections of to-many-related objects. Entries for which -valueForKey: returns nil have NSNull as their value in the returned dictionary.
*/
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
/* Given a dictionary containing keyed attribute values, to-one-related objects, and/or collections of to-many-related objects, set the keyed values. Dictionary entries whose values are NSNull result in -setValue:nil forKey:key messages being sent to the receiver.
*/
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
@end
@interface NSArray<ObjectType>(NSKeyValueCoding)
/* Return an array containing the results of invoking -valueForKey: on each of the receiver's elements. The returned array will contain NSNull elements for each instance of -valueForKey: returning nil.
*/
- (id)valueForKey:(NSString *)key;
/* Invoke -setValue:forKey: on each of the receiver's elements.
*/
- (void)setValue:(nullable id)value forKey:(NSString *)key;
@end
@interface NSDictionary<KeyType, ObjectType>(NSKeyValueCoding)
/* Return the result of sending -objectForKey: to the receiver.
*/
- (nullable ObjectType)valueForKey:(NSString *)key;
@end
@interface NSMutableDictionary<KeyType, ObjectType>(NSKeyValueCoding)
/* Send -setObject:forKey: to the receiver, unless the value is nil, in which case send -removeObjectForKey:.
*/
- (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;
@end
@interface NSOrderedSet<ObjectType>(NSKeyValueCoding)
/* Return an ordered set containing the results of invoking -valueForKey: on each of the receiver's members. The returned ordered set might not have the same number of members as the receiver. The returned ordered set will not contain any elements corresponding to instances of -valueForKey: returning nil, nor will it contain duplicates.
*/
- (id)valueForKey:(NSString *)key API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/* Invoke -setValue:forKey: on each of the receiver's members.
*/
- (void)setValue:(nullable id)value forKey:(NSString *)key API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
@end
@interface NSSet<ObjectType>(NSKeyValueCoding)
/* Return a set containing the results of invoking -valueForKey: on each of the receiver's members. The returned set might not have the same number of members as the receiver. The returned set will not contain any elements corresponding to instances of -valueForKey: returning nil (in contrast with -[NSArray(NSKeyValueCoding) valueForKey:], which may put NSNulls in the arrays it returns).
*/
- (id)valueForKey:(NSString *)key;
/* Invoke -setValue:forKey: on each of the receiver's members.
*/
- (void)setValue:(nullable id)value forKey:(NSString *)key;
@end
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
@interface NSObject(NSDeprecatedKeyValueCoding)
/* Methods that were deprecated in Mac OS 10.4.
*/
+ (BOOL)useStoredAccessor API_DEPRECATED("Legacy KVC API", macos(10.0,10.4), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (nullable id)storedValueForKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.4), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (void)takeStoredValue:(nullable id)value forKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.4), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
/* Methods that were deprecated in Mac OS 10.3. Use the new, more consistently named, methods declared above instead.
*/
- (void)takeValue:(nullable id)value forKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (void)takeValue:(nullable id)value forKeyPath:(NSString *)keyPath API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (nullable id)handleQueryWithUnboundKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (void)handleTakeValue:(nullable id)value forUnboundKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (void)unableToSetNilForKey:(NSString *)key API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (NSDictionary *)valuesForKeys:(NSArray *)keys API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
- (void)takeValuesFromDictionary:(NSDictionary *)properties API_DEPRECATED("Legacy KVC API", macos(10.0,10.3), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
@end
#endif