-
Notifications
You must be signed in to change notification settings - Fork 51
KVO 实现原理
jiaxw32 edited this page Jun 6, 2020
·
6 revisions
-
实例化一个
Person
对象,在添加观察者前,打印变量(lldb) po [personA _ivarDescription] <Person: 0x60000377d9e0>: in Person: _name (NSString*): nil _age (long): 0 in NSObject: isa (Class): Person (isa, 0x10e8b36f0)
-
查看方法列表
(lldb) pmethods personA -a Class Methods: No methods were found Instance Methods: - (void).cxx_destruct 0x10e8aee10 - (id)name 0x10e8aed60 - (void)setName:(id)arg0 0x10e8aed90 - (long long)age 0x10e8aedd0 - (void)setAge:(long long)arg0 0x10e8aedf0
-
打印实例变量,添加观察者后
isa
指针指向了新了对象NSKVONotifying_Person
(lldb) po [personA _ivarDescription] <Person: 0x60000377d9e0>: in Person: _name (NSString*): nil _age (long): 0 in NSObject: isa (Class): NSKVONotifying_Person (isa, 0x600000548630)
-
查看
NSKVONotifying_Person
父类(lldb) po class_getSuperclass((id)0x600000548630) Perso
-
打印方法列表
(lldb) pmethods personA -a Class Methods: No methods were found Instance Methods: - (void)setName:(id)arg0 0x7fff258dba8b - (Class)class 0x7fff258da515 - (void)dealloc 0x7fff258da27a - (bool)_isKVOA 0x7fff258da272
-
打印
IMP
(lldb) print (IMP)0x7fff258dba8b (IMP) $78 = 0x00007fff258dba8b (Foundation`_NSSetObjectValueAndNotify) (lldb) print (IMP)0x7fff258da515 (IMP) $79 = 0x00007fff258da515 (Foundation`NSKVOClass) (lldb) print (IMP)0x7fff258da27a (IMP) $80 = 0x00007fff258da27a (Foundation`NSKVODeallocate) (lldb) print (IMP)0x7fff258da272 (IMP) $81 = 0x00007fff258da272 (Foundation`NSKVOIsAutonotifying)
-
直接访问属性赋值,会触发 KVO
personAB.name = @"John";
-
使用 KVC 为属性赋值,也会触发 KVO
[personAB setValue:@"Jack" forKey:@"name"];
-
直接访问私有变量赋值,不会触发 KVO
//Person.h @interface Person : NSObject{ NSString *_nickname; } //Person.m - (void)setNickName:(NSString *)nickname{ _nickname = nickname; } //ViewController.m [personAB setNickName:@"Air Jonh"];
-
使用 KVC 为私有变量赋值,会触发 KVO
[personAB setValue:@"Big Boss" forKey:@"_nickname"];
-
调用堆栈
* frame #0: 0x000000010e8ae9c2 KVOExplorer`-[ViewController observeValueForKeyPath:ofObject:change:context:](self=0x00007f913a409d70, _cmd="observeValueForKeyPath:ofObject:change:context:", keyPath=@"name", object=0x000060000377da20, change=0x000060000227f980, context=0x0000000000000000) at ViewController.m:90:18 frame #1: 0x00007fff258de357 Foundation`NSKeyValueNotifyObserver + 329 frame #2: 0x00007fff258e18f3 Foundation`NSKeyValueDidChange + 502 frame #3: 0x00007fff258e11f5 Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 741 frame #4: 0x00007fff258e1af2 Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68 frame #5: 0x00007fff258dbb98 Foundation`_NSSetObjectValueAndNotify + 269 frame #6: 0x000000010e8ae693 KVOExplorer`-[ViewController viewDidLoad](self=0x00007f913a409d70, _cmd="viewDidLoad") at ViewController.m:79:5
-
打印实例变量
(lldb) po [personA _ivarDescription] <Person: 0x60000377d9e0>: in Person: _name (NSString*): nil _age (long): 0 in NSObject: isa (Class): Person (isa, 0x10e8b36f0)
-
打印方法列表
(lldb) pmethods personA -a Class Methods: No methods were found Instance Methods: - (void).cxx_destruct 0x10e8aee10 - (id)name 0x10e8aed60 - (void)setName:(id)arg0 0x10e8aed90 - (long long)age 0x10e8aedd0 - (void)setAge:(long long)arg0 0x10e8aedf0
当定义一个 NSKVONotifying_Person
类时,系统无法动态创建 NSKVONotifying_Persson
类,导致 KVO 失效,错误如下:
[general] KVO failed to allocate class pair for name NSKVONotifying_Person, automatic key-value observing will not work for this class