iOS笔记 - KVC实现原理
KVC实现原理
1 - 我们知道使用 KVC赋值会触发 KVO,比如 setValue: forKeyPath:方法实现原理如图所示
接下来我们就一步步进行验证
// - Person.h
1 #import2 @interface Person : NSObject{ 3 @public 4 NSString *_name; 5 6 // 验证 KVC访问成员变量的机制 7 // int _age; 8 // int _isAge; 9 // int age; 10 int isAge; 11 } 12 13 @end
// - Person.m
1 #import "Person.h" 2 @implementation Person 3 4 // KVC 赋值步骤 5 6 // 步骤一: 7 // 存在 setAge方法就调用该方法 8 //-(void)setAge:(int)age{ 9 // 10 // NSLog(@"启用 setAge"); 11 // 12 // _age = age; 13 //} 14 15 16 // 步骤二: 17 // 不存在 setAge方法就调用该方法 18 //-(void)_setAge:(int)age{ 19 // 20 // NSLog(@"启用 _setAge"); 21 // _age = age; 22 //} 23 24 // 步骤三:setAge、_setAge两方法都不存在,则调用该方法 25 // 是否允许去访问成员变量 26 + (BOOL)accessInstanceVariablesDirectly{ 27 28 29 // 情况一 30 // 默认 YES 31 return YES; // 则去访问成员变量 32 33 // 查询成员变量的顺序:依次 _key、_isKey、key、isKey 34 // 该示例中就是 _age、_isAge、age、isAge 35 // 如果没有查到成员变量,这进入 步骤四 36 37 // 情况二 38 // return NO; //则直接 步骤四 39 40 } 41 42 // 步骤四:调用该方法并抛出 NSUnknownKeyException异常 43 - (void)setValue:(id)value forUndefinedKey:(NSString *)key{ 44 45 } 46 47 @end
// - TObServer.m:新建 TObServer继承自 NSObject,实现监听方法
1 #import "TObServer.h" 2 @implementation TObServer 3 4 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionaryid> *)change context:(void *)context{ 5 6 NSLog(@"%@ --- %@",keyPath,change); 7 } 8 9 @end
// - ViewController.m
1 #import "ViewController.h" 2 #import "Person.h" 3 #import "TObServer.h" 4 @interface ViewController() 5 6 @end 7 8 @implementation ViewController 9 10 - (void)viewDidLoad { 11 [super viewDidLoad]; 12 self.view.backgroundColor = [UIColor cyanColor]; 13 14 TObServer *observer = [TObServer new]; 15 Person *p1 = [Person new]; 16 17 [p1 addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 18 19 // 方式一 20 // [p1 setValue:@12 forKey:@"age"]; 21 22 // 方式二:根据路径赋值,功能更强大 23 [p1 setValue:@21 forKeyPath:@"age"]; 24 25 // 注意 26 // 状况一:如果存在 setter方法(_setAge:/setAge),则触发 KVC我们很好理解 27 // 其实就是 setValue:forKeyPath: 去调用了 setter方法 28 // 并且调用 willChangeValueForKey、didChangeValueForKey触发监听 29 30 31 // 状况二:如果不存在 setter方法,只存在成员变量,那么依旧可以触发监听 32 // 就是说 setValue:forKeyPath会寻找 setter方法,没有的话就寻找其成员变量 33 // 只要可以找到任何一种结果,就会启动 willChangeValueForKey、didChangeValueForKey触发监听 34 35 [p1 removeObserver:observer forKeyPath:@"age"]; 36 } 37 38 @end
日志信息:只存在成员变量依旧触发监听
2 - KVC取值原理(不再一步步验证)