KVO源码

931 阅读10分钟

本文将利用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源码中添加观察者时整体的大致流程是什么?

  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/

最后

汇编读起来确实不宜,但好在汇编相关的资料并不少。如果各位大佬发现有哪里说的不对地方,请评论区留言
交流共勉!
尊重原创,转发求表明出处