本文主要介绍kvo是如何查找变量然后赋值,以及通过key取出值的
准备工作
Animal
类
1 | // .h |
main.m
1 | #import <Foundation/Foundation.h> |
setValue:forkey:
这个时候运行上面的代码会报下面的错误
1 | Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Animal 0x10052f6b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key age.' |
下面对Animal
代码进行改造
Animal.m
改造1
1 | - (void)setAge:(int)age { |
程序正常运行并打印
1 | setAge---12 |
Animal.m
改造2
1 | //- (void)setAge:(int)age { |
程序正常输出
1 | _setAge---12 |
Animal.m
改造3
1 | - (void)setAge:(int)age { |
程序正常输出并且只输出
1 | setAge---12 |
首先得出下面的结论
setValue:forkey:
会调用调用-set<Key>:
方法;- 当-set
:不存在的时候回调用-_set :方法.
Animal.m
改造4
1 | #import "Animal.h" |
先打个断点,然后看下面控制台的值的情况
这个时候是赋值给了_age
Animal.m
改造5
1 | #import "Animal.h" |
这次注释掉_age
这次给了_isAge
同理分别注释下其他的2个
得出第二个结论
- 当
-set<Key>:
和-_set<Key>:
方法都没实现时kvc
会按照_<key>
->_is<Key>
-><key>
->is<Key>
进行赋值
Animal.m
改造6
1 | #import "Animal.h" |
运行程序发现奔溃了
accessInstanceVariablesDirectly
表示当没有set方法的时候要不要继续查找成员变量,默认是需要
得出kvc赋值最终的结论
用一张图来表示,图上是以具体的属性名称来表示的
valueForKey:
改造代码Animal
1 | // .h |
main.m
1 | #import <Foundation/Foundation.h> |
运行程序发现崩溃了
下面改造Animal.m
代码
Animal
改造1
1 | - (int)getName { |
输出
1 | 12 |
Animal
改造2
1 | //- (int)getName { |
输出
1 | 13 |
Animal
改造3
1 | //- (int)getName { |
输出
1 | 14 |
Animal
改造4
1 | //- (int)getName { |
输出
1 | 15 |
Animal
改造5
1 | //- (int)getName { |
输出
1 | 16 |
同样先得出下面的结论
- valueforkey:方法调用方法的顺序是
get<Key>
-><key>
->is<Key>
->_get<Key>
->_<key>
Animal
改造6
1 | //.h |
main.m
1 | #import <Foundation/Foundation.h> |
运行程序发现输出
1 | a |
分别注释以下代码
1 | @interface Animal : NSObject |
发现输出
1 | b |
注释后面的会发现分别输出c
,d
得出以下结论
- 当通过方法找不到时,会按照
_<key>
->_<isKey>
-><key>
->is<Key>
的顺序查找赋值
同样当我们将
1 |
|
就不会往下查找成员变量了,总结后就是下面的这张图
最后
不会是取值还是赋值,kvc
都是先通过方法操作,发现没有对应的方法的时候,会根据accessInstanceVariablesDirectly
方法决定是否进行找到对应的成员变量进行操作