一 Getter
- (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来取值
- 1.通过
getter
方法搜索实例,按照get<Key>
, <key>
, is<Key>
, _<key>的顺序查找
getter`方法。如果发现符合的方法,就调用对应的方法并拿着结果跳转到第五步。否则,就继续到下一步。 - 2.如果没有找到简单的
getter
方法,则搜索其匹配模式的方法countOf<Key>
、objectIn<Key>AtIndex:
、<key>AtIndexes:
。
如果找到其中的第一个和其他两个中的一个,则就会返回一个可以响应NSArray
所有方法的代理集合(它是NSKeyValueArray
,是NSArray
的子类)。或者说给这个代理集合发送属于NSArray
的方法,就会以countOf<Key>
,objectIn<Key>AtIndex
或<Key>AtIndexes
这几个方法组合的形式调用。否则,继续到第三步。
代理对象随后将NSArray
接收到的countOf<Key>
、objectIn<Key>AtIndex:
、<key>AtIndexes:
的消息给符合KVC
规则的调用方。
当代理对象和KVC
调用方通过上面方法一起工作时,就会允许其行为类似于NSArray
一样。 - 3.如果没有找到
NSArray
简单存取方法,或者NSArray
存取方法组。那么会同时查找countOf<Key>
、enumeratorOf<Key>
、memberOf<Key>:
命名的方法。
如果找到三个方法,则创建一个集合代理对象,该对象响应所有NSSet
方法并返回。否则,继续执行第四步。
给这个代理对象发NSSet
的消息,就会以countOf<Key>
,enumeratorOf<Key>
,memberOf<Key>
组合的形式调用。 - 4.如果没有发现简单
getter
方法,或集合存取方法组,以及接收类方法accessInstanceVariablesDirectly
是返回YES
的。搜索一个名为_<key>
、_is<Key>
、<key>
、is<Key>
的实例,根据他们的顺序。
如果发现对应的实例,则立刻获得实例可用的值并跳转到第五步,如果重写了类方法+ (BOOL)accessInstanceVariablesDirectly
返回NO的话,那么会直接调用valueForUndefinedKey:
。 - 5.如果取回的是一个对象指针,则直接返回这个结果。
如果取回的是一个基础数据类型,但是这个基础数据类型是被NSNumber
支持的,则存储为NSNumber
并返回。
如果取回的是一个不支持NSNumber
的基础数据类型,则通过NSValue
进行存储并返回。 - 6.如果所有情况都失败,则调用
valueForUndefinedKey:
方法并抛出异常,这是默认行为。但是子类可以重写此方法。
二 Setter
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值
- 1.查找
set<Key>:
或_set<Key>
命名的setter
,按照这个顺序,如果找到的话,代码通过setter
方法完成设置。 - 2.如果没有找到
setter
方法,KVC机制会检查+ (BOOL)accessInstanceVariablesDirectly
的返回值,如果accessInstanceVariablesDirectly
类属性返回YES
,则查找一个命名规则为_<key>
、_is<Key>
、<key>
、is<Key>
的实例变量。根据这个顺序,如果发现则将value
赋值给实例变量,如果返回值为NO,KVC会执行setValue:forUndefinedKey:
方法。 - 3.如果没有发现
setter
或实例变量,则调用setValue:forUndefinedKey:
方法,并默认提出一个异常,但是一个NSObject
的子类可以提出合适的行为。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。