KVO

本文将利用holper disassembler class dump 窥探KVO背后的原理。

准备工作

  • holper disassembler
  • class dump
  • LLDB 调试指令如:&arg0 symbol breakpoint (SEL)&arg0 frame 等等
  • 汇编相关知识。操作符 寄存器等

希望解决的问题

  • KVO注册期间发生经过了什么,内部组成是什么
  • KVO如何实现弱引用
  • KVO的observationInfo如何实现

    Foundation.framework

    通过class dump 查看 Foundation.framework 的目录结构及对象结构,这里有一篇继承结构说明

通过holper disassembler 反编译 Foundation.framework 的可执行文件,切记不是.tdb结尾的文件。反编译成功后,搜索“addObserver”关键字,可便看见如下方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void -[NSObject addObserver:forKeyPath:options:context:](void * self, void * _cmd, void * arg2, void * arg3, unsigned long long arg4, void * arg5) {

/*
* 参数说明 self, _cmd 对应OC的方法中target selector,
* arg2:observer对象
* arg3:path
* arg4:options
* arg5:context
*/
pthread_mutex_lock(__NSKeyValueObserverRegistrationLock);
*__NSKeyValueObserverRegistrationLockOwner = pthread_self();
rax = object_getClass(self);

// 获取NSKeyValueUnnestedProperty(继承与NSKeyValueProperty) 对象
rax = _NSKeyValuePropertyForIsaAndKeyPath(rax, arg3, arg2);
//真正的方法
[self _addObserver:arg2 forProperty:rax options:arg4 context:arg5];
*__NSKeyValueObserverRegistrationLockOwner = 0x0;
pthread_mutex_unlock(__NSKeyValueObserverRegistrationLock);
if (0x0 != 0x0) {

objc_exception_rethrow();
}
return;
}

NSKeyValueProperty

NSKeyValueProperty对象结构NSKeyValueUnnestedProperty对象结构

获取NSKeyValueProperty对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

_NSKeyValuePropertyForIsaAndKeyPath(int arg0, int arg1, int arg2){


/*
* arg0: isa
* arg1: keyPath
* arg2: observer对象
* _NSKeyValueProperties 为全局CFMutableSetRef
*/

r14 = arg1;
r15 = arg0;
var_40 = 0x0;

// 获取NSKeyValueContainerClass
var_38 = __NSKeyValueContainerClassForIsa(arg0, arg1, arg2);
var_30 = r14;
// _NSKeyValueProperties 为缓存 NSKeyValueProperty的set
if (*_NSKeyValueProperties != 0x0) {
rax = CFSetGetValue(*_NSKeyValueProperties, 0x0);
rbx = rax;
//如果 NSKeyValueProperty不存在
if (rax == 0x0) {
*(var_70 + 0x18) = *_kOSThermalNotificationPressureLevelName;
*(var_70 + 0x10) = *_kIOMasterPortDefault;
rcx = *_kCFTypeSetCallBacks;
*(var_70 + 0x8) = *_kCFURLIsRegularFileKey;
*var_70 = rcx;
*(var_70 + 0x20) = _NSKeyValuePropertyIsEqual;
*(var_70 + 0x28) = _NSKeyValuePropertyHash;
rax = CFSetCreateMutable(0x0, 0x0, var_70);
// 根据 isa keyPath CFSet来决定实例化哪种NSKeyValueProperty(下面三种)
// NSKeyValueNestedProperty NSKeyValueUnnestedProperty NSKeyValueComputedProperty
rbx = _NSKeyValuePropertyForIsaAndKeyPathInner(r15, r14, rax);
rax = CFRelease(rax);
if (0x0 == 0x0) {
rax = rbx;
rbx = stack[2042];
r12 = stack[2043];
r13 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0x78;
rbp = stack[2047];
}
else {
rax = objc_exception_rethrow();
}
}
else {
rax = rbx;
rbx = stack[2042];
r12 = stack[2043];
r13 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0x78;
rbp = stack[2047];
}
}
else {
*(var_70 + 0x18) = *_kOSThermalNotificationPressureLevelName;
*(var_70 + 0x10) = *_kIOMasterPortDefault;
rcx = *_kCFTypeSetCallBacks;
*(var_70 + 0x8) = *_kCFURLIsRegularFileKey;
*var_70 = rcx;
*(var_70 + 0x20) = _NSKeyValuePropertyIsEqual;
*(var_70 + 0x28) = _NSKeyValuePropertyHash;
rax = CFSetCreateMutable(0x0, 0x0, var_70);
//同上面 “_NSKeyValuePropertyForIsaAndKeyPathInner”
rbx = _NSKeyValuePropertyForIsaAndKeyPathInner(r15, r14, rax);
rax = CFRelease(rax);
if (0x0 == 0x0) {
rax = rbx;
rbx = stack[2042];
r12 = stack[2043];
r13 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0x78;
rbp = stack[2047];
}
else {
rax = objc_exception_rethrow();
}
}
return rax;

}

NSKeyValueContainerClass

NSKeyValueContainerClass类结构

获取NSKeyValueContainerClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
int __NSKeyValueContainerClassForIsa(int arg0, int arg1, int arg2) {

/*
* arg0: isa
* arg1: keyPath
* arg2: observer对象
*/

/*
* 这里面多次出现的“*__NSKeyValueContainerClassForIsa”,其实是局部的静态变量
* 所以 NSKeyValueContainerClassPerOriginalClass 就是一个static 的CFMutableDictionary
*/
rdx = arg2;
rsi = arg1;
//如果缓存的Key 与 isa 不一致,注意这里的isa可能是"NSKVONotifying_"也可能是原类,在第二次添加时则为派生类
if (*__NSKeyValueContainerClassForIsa.isaCacheKey != arg0) {
rdi = *__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass;
r15 = rdi;
//获得原类的 isa,里面会判断根据“isKVOA”方法的实现来判断返回原类
r14 = __NSKVONotifyingOriginalClassForIsa(rdi);
// 如果存在缓存
if (*__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass != 0x0) {
//根据isa 取出 NSKeyValueContainerClass
rax = CFDictionaryGetValue(*__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass, r14);
rbx = rax;
//取不到
if (rax == 0x0) {
//初始化 NSKeyValueContainerClass 对象 并存入缓存
r12 = _objc_msgSend;
rax = [NSKeyValueContainerClass alloc];
rax = [rax initWithOriginalClass:r14];
rbx = rax;
rax = CFDictionarySetValue(*__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass, r14, rax);
rax = [rbx release];
}
}
else {
// 如果不存在缓存,则初始化静态变量NSKeyValueContainerClassPerOriginalClass(CFMutableDictionary)
*__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass = CFDictionaryCreateMutable(0x0, 0x0, 0x0, _kCFTypeDictionaryValueCallBacks);
r12 = _objc_msgSend;
//初始化 NSKeyValueContainerClass 对象 并存入缓存
rax = [NSKeyValueContainerClass alloc];
rax = [rax initWithOriginalClass:r14];
rbx = rax;
rax = CFDictionarySetValue(*__NSKeyValueContainerClassForIsa.NSKeyValueContainerClassPerOriginalClass, r14, rax);
rax = [rbx release];
}
更新静态变量缓存的值
*__NSKeyValueContainerClassForIsa.isaCacheKey = r15;
*__NSKeyValueContainerClassForIsa.cachedContainerClass = rbx;
}
else {
//cacheKey 相同 则直接返回 cachedContainerClass
rbx = *__NSKeyValueContainerClassForIsa.cachedContainerClass;
}
rax = rbx;
rbx = stack[2043];
r12 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0x28;
rbp = stack[2047];
return rax;
}

经过上面两步准备工作之后,会调用下的方法并传入准备好的NSKeyValueProperty,其中部分枚举定义可参考NSKeyValueObserving.h

_addObserver真正的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

void -[NSObject _addObserver:forProperty:options:context:](void * self, void * _cmd, void * arg2, void * arg3, unsigned long long arg4, void * arg5) {

/*
* arg2: observer对象
* arg3: NSKeyValueProperty子类对象
* arg4: options
* arg5: context
*/

rsi = _cmd;
var_40 = arg5;
r12 = arg4;
r13 = arg3;
var_38 = arg2;
r14 = self;
// 0x4 为枚举 NSKeyValueObservingOptionInitial
if ((r12 & 0x4) != 0x0) {
var_30 = 0x0;
//取出 property 的 keyPath
r15 = [r13 keyPath];
*__NSKeyValueObserverRegistrationLockOwner = 0x0;
rax = pthread_mutex_unlock(__NSKeyValueObserverRegistrationLock);
// 0x1 NSKeyValueObservingOptionNew
if ((r12 & 0x1) == 0x0) {
//初始化值
rax = 0x0;
}
else {
// [self valueForKeyPath:keyPath]
rax = [r14 valueForKeyPath:r15];
if (rax == 0x0) {
rax = [NSNull null];
}
}
stack[2031] = 0x0;
stack[2030] = 0x0;
stack[2029] = rax;
stack[2028] = 0x0;
stack[2032] = 0x0;
// NSKeyValueObservingOptionInitial 时 发送通知
rax = _NSKeyValueNotifyObserver(var_38, 0x0, r14, var_40, 0x0, 0x0, 0x1);
r15 = 0x0;
rax = [0x0 release];
if (0x1 != 0x0) {
rax = pthread_mutex_lock(__NSKeyValueObserverRegistrationLock);
*__NSKeyValueObserverRegistrationLockOwner = pthread_self();
}
if (0x0 == 0x0) {
// 获取oldObservationInfo 内部会根据containerClass是否缓存了“observationInfo”
//来调用cachedObservationInfoImplementation 或者 直接获取object的observationInfo对象
r15 = __NSKeyValueRetainedObservationInfoForObject(r14, r13->_containerClass);
if (!(BIT_TEST(r12, 0x8))) {
rax = _CFGetTSD(0x15);
if (rax != 0x0) {
r9 = *(rax + 0x10);
}
else {
r9 = 0x0;
}
}
else {
r9 = 0x0;
}
// 获取newObservationInfo ,创建逻辑 下面有说明
r12 = __NSKeyValueObservationInfoCreateByAdding(r15, var_38, r13, r12, var_40, r9, 0x0, 0x1);
r8 = 0x0;
// 通过遍历替换老的ObservationInfo
rax = __NSKeyValueReplaceObservationInfoForObject(r14, r13->_containerClass, r15, r12);
rax = [r13 object:r14 didAddObservance:*0x1 recurse:0x1];

// 核心方法: 获取property中已经修改过的class,这里会完成对原类一些方法的复写,这里不再说明(因为结果网上一大把- -)
rax = [r13 isaForAutonotifying];
rbx = rax;
if ((rax != 0x0) && (object_getClass(r14) != rbx)) {
// 通过 object_setClass()修改isa指针, 设置自己的class为property的isaForAutonotifying
rax = object_setClass(r14, rbx);
}
r13 = 0x0;
rbx = @selector(release);
rax = _objc_msgSend(r12, rbx);
if (r15 != 0x0) {
rax = _objc_msgSend(r15, rbx);
}
if (0x0 == 0x0) {
rbx = stack[2042];
r12 = stack[2043];
r13 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0xa8;
rbp = stack[2047];
}
else {
rax = objc_exception_rethrow();
}
}
else {
rax = objc_exception_rethrow();
}
}
else {
// 大部分都是跟上面一样的逻辑 这里不再赘述
r15 = __NSKeyValueRetainedObservationInfoForObject(r14, r13->_containerClass);
if (!(BIT_TEST(r12, 0x8))) {
rax = _CFGetTSD(0x15);
if (rax != 0x0) {
r9 = *(rax + 0x10);
}
else {
r9 = 0x0;
}
}
else {
r9 = 0x0;
}
r12 = __NSKeyValueObservationInfoCreateByAdding(r15, var_38, r13, r12, var_40, r9, 0x0, 0x1);
r8 = 0x0;
rax = __NSKeyValueReplaceObservationInfoForObject(r14, r13->_containerClass, r15, r12);
rax = [r13 object:r14 didAddObservance:*0x1 recurse:0x1];
rax = [r13 isaForAutonotifying];
rbx = rax;
if ((rax != 0x0) && (object_getClass(r14) != rbx)) {
rax = object_setClass(r14, rbx);
}
r13 = 0x0;
rbx = @selector(release);
rax = _objc_msgSend(r12, rbx);
if (r15 != 0x0) {
rax = _objc_msgSend(r15, rbx);
}
if (0x0 == 0x0) {
rbx = stack[2042];
r12 = stack[2043];
r13 = stack[2044];
r14 = stack[2045];
r15 = stack[2046];
rsp = rsp + 0xa8;
rbp = stack[2047];
}
else {
rax = objc_exception_rethrow();
}
}
return;
}

NSKeyValueObserverInfo

创建NSKeyValueObserverInfo的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
int __NSKeyValueObservationInfoCreateByAdding(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) {

/*
* arg0: NSKeyValueObservationInfo 对象
* arg1: observer 对象
* arg2: NSKeyValueProperty 对象
* arg3: options
* arg4: context
* arg5: originalObservable
* arg6: cacheHit
* arg7: addedObservance
*/

var_48 = arg5;
r12 = arg4;
r15 = arg3;
var_40 = arg2;
rbx = arg1;
r14 = arg0;
os_unfair_lock_lock_with_options(_NSKeyValueObservationInfoCreationLock, 0x10000, arg2, arg3, arg4, arg5, stack[2035], stack[2036]);

// 使用弱引用表NSKeyValueShareableObservationInfos缓存观察者对象
if (*_NSKeyValueShareableObservationInfos == 0x0) {
var_30 = r12;
rax = [NSPointerFunctions alloc];
rax = [rax initWithOptions:0x5];
r13 = rax;
[rax setHashFunction:_NSKeyValueShareableObservationInfoNSHTHash];
[r13 setIsEqualFunction:_NSKeyValueShareableObservationInfoNSHTIsEqual];
r14 = r14;
rbx = rbx;
*_NSKeyValueShareableObservationInfos = [[NSHashTable alloc] initWithPointerFunctions:r13 capacity:0x0];
[r13 release];
r12 = var_30;
}
// isa不存在初始化 NSKeyValueShareableObservationInfoKey 并记录isa
if (*_NSKeyValueShareableObservationInfoKeyIsa == 0x0) {
*_NSKeyValueShareableObservationInfoKeyIsa = [NSKeyValueShareableObservationInfoKey self];
}
rdx = *__NSKeyValueObservationInfoCreateByAdding.shareableObservationInfoKey;
if (rdx == 0x0) {
r13 = rbx;
rbx = r15;
rax = [NSKeyValueShareableObservationInfoKey alloc];
rax = [rax init];
r15 = rbx;
rbx = r13;
rdx = rax;
*__NSKeyValueObservationInfoCreateByAdding.shareableObservationInfoKey = rax;
}
//上下这几行 是建立索引条件,_NSKeyValueShareableObservationInfos 将以这些参数判断是否存在老的NSKeyValueObservationInfo
rdx->_addingNotRemoving = 0x1;
rdx->_baseObservationInfo = r14;
rdx->_additionObserver = rbx;
rdx->_additionProperty = var_40;
rdx->_additionOptions = r15 & 0xfffffffffffffffb;
rdx->_additionContext = r12;
rdx->_additionOriginalObservable = var_48;
r13 = rbx;
rbx = r14;
rsi = r12;
//查找缓存里 是否已经包含 和 baseObservationInfo + observance(observer, property, options, context) 一样的 observationInfo
//避免不必要的创建
r12 = [*_NSKeyValueShareableObservationInfos member:rdx];
rax = *__NSKeyValueObservationInfoCreateByAdding.shareableObservationInfoKey;
rax->_additionOriginalObservable = 0x0;
rax->_additionObserver = 0x0;
rax->_baseObservationInfo = 0x0;
//如果存在缓存
if (r12 != 0x0) {
//observance必定就是已存在的info.observance列表最后一个, 因为判断equal就是按照这个原则去判断的
[r12 retain];
*(int8_t *)arg6 = 0x1;
*arg7 = [r12->_observances lastObject];
}
else {
// 不存在初始化 _NSKeyValueShareableObservances 缓存
r12 = r13;
r14 = r15;
r13 = rsi;
var_30 = rbx;
rdi = *_NSKeyValueShareableObservances;
if (rdi == 0x0) {
rax = [NSHashTable weakObjectsHashTable];
rax = [rax retain];
rdi = rax;
*_NSKeyValueShareableObservances = rax;
}
// 跟 shareableObservationInfoKey 同样的逻辑,初始化_NSKeyValueShareableObservances的查找条件
rdx = *__NSKeyValueObservationInfoCreateByAdding.shareableObservanceKey;
rcx = var_40;
if (rdx == 0x0) {
rax = [NSKeyValueShareableObservanceKey alloc];
rax = [rax init];
rcx = rcx;
rdx = rax;
*__NSKeyValueObservationInfoCreateByAdding.shareableObservanceKey = rax;
rdi = *_NSKeyValueShareableObservances;
}
//同上
r15 = r12;
rdx->_observer = r12;
rdx->_property = rcx;
rdx->_options = rdx->_options & 0x80 | r14 & 0x7b;
rdx->_context = r13;
r12 = var_48;
rdx->_originalObservable = r12;
var_38 = [rdi member:rdx];
rax = *__NSKeyValueObservationInfoCreateByAdding.shareableObservanceKey;
rax->_originalObservable = 0x0;
rax->_observer = 0x0;
rbx = var_38;
if (rbx != 0x0) {
[rbx retain];
r14 = var_30;
}
else {
// 没有找到, 则创建observance
rax = [NSKeyValueObservance alloc];
rax = [rax _initWithObserver:r15 property:var_40 options:r14 context:r13 originalObservable:r12];
rbx = rax;
var_38 = rax;
r14 = var_30;
// 可以缓存, 放入NSKeyValueShareableObservances中
if (rbx->_cachedIsShareable < 0x0) {
[*_NSKeyValueShareableObservances addObject:rbx];
}
}
r15 = arg6;
如果baseObservationInfo存在
if (r14 != 0x0) {
// 复制baseObservationInfo并追加observance
r12 = [r14 _copyByAddingObservance:rbx];
}
else {
// 创建新的ObservationInfo
r12 = [[NSKeyValueObservationInfo alloc] _initWithObservances:var_38 count:0x1 hashValue:0x0];
rbx = *var_38;
}
[rbx release];
rbx = arg7;
// 允许缓存, 添加到NSKeyValueShareableObservationInfos中
if (r12->_cachedIsShareable != 0x0) {
[*_NSKeyValueShareableObservationInfos addObject:r12];
}
*(int8_t *)r15 = 0x0;
*rbx = var_38;
}
os_unfair_lock_unlock(_NSKeyValueObservationInfoCreationLock);
rax = r12;
return rax;
}

我们可以发现上面针对observationInfo都是以弱引用的方式存贮的,那么真正是谁来管理observationInfo的生命周期呢

生命周期

我们可从这几个方面找到答案

  • ObservationInfo 的setter getter方法
  • 设置breakpoint 在dealloc 方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    void -[NSObject setObservationInfo:](void * self, void * _cmd, void * arg2) {
    r14 = arg2;
    rbx = self;
    //主角登场,全局管理ObservationInfo的CFDictionary
    rdi = *_NSKeyValueObservationInfoPerObject;
    if (rdi == 0x0) {
    rax = CFDictionaryCreateMutable(0x0, 0x0, 0x0, 0x0);
    rdi = rax;
    *_NSKeyValueObservationInfoPerObject = rax;
    }
    rsi = !rbx;
    if (r14 != 0x0) {
    rdx = r14;
    CFDictionarySetValue(rdi, rsi, rdx);
    }
    else {
    CFDictionaryRemoveValue(rdi, rsi);
    }
    return;
    }

__NSKeyValueRemoveObservationInfoForObject 在这个方法里面我们也能看到 _NSKeyValueObservationInfoPerObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void _NSKVODeallocate(int arg0, int arg1) {
r12 = arg1;
r15 = arg0;
if (*_NSKVODeallocate.onceToken != 0xffffffffffffffff) {
dispatch_once(_NSKVODeallocate.onceToken, ^ { /* block implemented at ___NSKVODeallocate_block_invoke */ });
}
rax = object_getClass(r15);
rbx = rax;
if (class_getMethodImplementation(rax, @selector(observationInfo)) != *_NSKVODeallocate.NSObjectObservationInfoImp) {
r14 = 0x0;
}
else {
r14 = class_getMethodImplementation(rbx, @selector(setObservationInfo:)) == *_NSKVODeallocate.NSObjectSetObservationInfoImp ? 0x1 : 0x0;
}
// 获取object对应的observationInfo
r13 = __NSKeyValueRetainedObservationInfoForObject(r15, 0x0);
// 获取notifyInfo
rax = object_getIndexedIvars(rbx);
var_38 = rax;
// 调用object原来的dealloc实现
rbx = class_getInstanceMethod(*rax, r12);
if (r14 != 0x0) {
// observationInfo不存在才对, 如果还存在, 说明没有正确地移除observer
method_invoke(r15, 0x0);
if (r13 != 0x0) {
__NSKeyValueRemoveObservationInfoForObject(r15);
[r13 release];
}
if (0x0 != 0x0) {
objc_exception_rethrow();
}
}
else {
*var_50 = r15;
*(var_50 + 0x8) = r13;
*(var_50 + 0x10) = 0x0;
// 移除watcher
__NSKeyValueAddObservationInfoWatcher(var_50);
method_invoke(r15, rbx);
if (var_48 != 0x0) {
r14 = dyld_get_program_sdk_version();
*(int8_t *)var_29 = 0x0;
rbx = (var_29 == 0x0 ? 0x1 : 0x0) | (CFPreferencesGetAppBooleanValue(@"NSKVODeallocateCleansUpBeforeThrowing", *_kCFPreferencesCurrentApplication, var_29) == 0x0 ? 0x1 : 0x0);
if ((r14 <= 0x7ffff) && (rbx != 0x0)) {
_NSLog(@"An instance %p of class %@ was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debu…", r15, *var_38);
_NSKVODeallocateBreak(r15);
}
else {
r14 = [var_48 description];
if (rbx == 0x0) {
__NSKeyValueRemoveObservationInfoForObject(var_50);
}
rdx = *_NSInternalInconsistencyException;
[NSException raise:rdx format:@"An instance %p of class %@ was deallocated while key value observers were still registered with it. Current observation info: %@"];
}
}
__NSKeyValueRemoveObservationInfoWatcher(var_50);
[var_48 release];
if (0x0 != 0x0) {
objc_exception_rethrow();
}
}
return;
}

总结

KVO源码中添加观察者时整体的大致流程是什么?

  1. 将keyPath、class等信息封装成NSKeyValueProperty,分别解析一般属性(@”aa”)、可计算属性(@”@aa”)、属性链(@”aa.bb.@cc.dd“),进行子类化,缓存在CFMutableSet中方便下次快速取出。
  2. 将NSKeyValueProperty、context、options、observer等信息封装成NSKeyValueObservance,缓存在NSHashTable中。
  3. 倘若设置了NSKeyValueObservingOptionInitial选项,会在注册观察服务时调用一次触发方法。
  4. 动态创建名为NSKVONotifying_+原来类名的新类,重写其dealloc、_isKVOA方法,再重写class方法,利用object_setClass()函数将其isa指针指向原先的类。
  5. 重写willChangeValueForKey:和didChangeValueForKey:方法,重写被观察属性的setter方法,在setter中先调用willChangeValueForKey:方法,然后调用父类的 setter 方法对成员变量赋值,之后再调用 didChangeValueForKey: 方法。
  6. didChangeValueForKey: 方法中会调用observeValueForKeyPath:ofObject:change:context:方法。

KVO中所封装组件的关系是怎样的?

  1. 将keyPath、class等信息封装成NSKeyValueProperty,使用CFMutableSet缓存NSKeyValueProperty。
  2. 将observer、property、options、context 、originalObservable等信息封装成NSKeyValueObservance,使用NSHashTable(NSKeyValueShareableObservationInfos)缓存。
  3. NSKeyValueObservationInfo与NSKeyValueObservance的关系是: NSKeyValueObservationInfo中有一个observances数组,数组里面是NSKeyValueObservance对象。
  4. 每一个object都有一个observationInfo属性(void *类型),它与NSKeyValueObservationInfo会相互转化。并交由_NSKeyValueObservationInfoPerObject全局管理

附上动态库的本地路径
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/