本文将利用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”关键字,可便看见如下方法。
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对象
_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
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真正的实现
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的逻辑
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 方法
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
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源码中添加观察者时整体的大致流程是什么?
- 将keyPath、class等信息封装成NSKeyValueProperty,分别解析一般属性(@"aa")、可计算属性(@"@aa")、属性链(@"aa.bb.@cc.dd"),进行子类化,缓存在CFMutableSet中方便下次快速取出。
- 将NSKeyValueProperty、context、options、observer等信息封装成NSKeyValueObservance,缓存在NSHashTable中。
- 倘若设置了NSKeyValueObservingOptionInitial选项,会在注册观察服务时调用一次触发方法。
- 动态创建名为NSKVONotifying_+原来类名的新类,重写其dealloc、_isKVOA方法,再重写class方法,利用object_setClass()函数将其isa指针指向原先的类。
- 重写willChangeValueForKey:和didChangeValueForKey:方法,重写被观察属性的setter方法,在setter中先调用willChangeValueForKey:方法,然后调用父类的 setter 方法对成员变量赋值,之后再调用 didChangeValueForKey: 方法。
- didChangeValueForKey: 方法中会调用observeValueForKeyPath:ofObject:change:context:方法。
KVO中所封装组件的关系是怎样的?
- 将keyPath、class等信息封装成NSKeyValueProperty,使用CFMutableSet缓存NSKeyValueProperty。
- 将observer、property、options、context 、originalObservable等信息封装成NSKeyValueObservance,使用NSHashTable(NSKeyValueShareableObservationInfos)缓存。
- NSKeyValueObservationInfo与NSKeyValueObservance的关系是: NSKeyValueObservationInfo中有一个observances数组,数组里面是NSKeyValueObservance对象。
- 每一个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/
最后
汇编读起来确实不宜,但好在汇编相关的资料并不少。如果各位大佬发现有哪里说的不对地方,请评论区留言
交流共勉!
尊重原创,转发求表明出处