美文网首页
ReactiveObjC 源码阅读笔记 (RACObserve(

ReactiveObjC 源码阅读笔记 (RACObserve(

作者: iOS资深入门 | 来源:发表于2021-08-22 22:52 被阅读0次

    常用KVO宏 RACObserve(<#TARGET#>, <#KEYPATH#>)

    使用:

        [[RACObserve(self.viewModel, model.number) takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id  _Nullable x) {
                // 响应监听
        }];
    

    源码

    • 宏定义
    #define _RACObserve(TARGET, KEYPATH) \
    ({ \
        __weak id target_ = (TARGET); \
        [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
    })
    
    #if __clang__ && (__clang_major__ >= 8)
    #define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
    #else
    #define RACObserve(TARGET, KEYPATH) \
    ({ \
        _Pragma("clang diagnostic push") \
        _Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \
        _RACObserve(TARGET, KEYPATH) \
        _Pragma("clang diagnostic pop") \
    })
    #endif
    
    • NSObject (RACPropertySubscribing) 创建订阅信号
    - (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer {
        return [[[self
            rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]
            map:^(RACTuple *value) {
                // -map: because it doesn't require the block trampoline that -reduceEach: uses
                return value[0];
            }]
            // 从 RacStream 继承来的 name 属性赋值,只 debug 时用。
            setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath];
    }
    
    - (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver {
        NSObject *strongObserver = weakObserver;
        keyPath = [keyPath copy];
    
        NSRecursiveLock *objectLock = [[NSRecursiveLock alloc] init];
        objectLock.name = @"org.reactivecocoa.ReactiveObjC.NSObjectRACPropertySubscribing";
    
        __weak NSObject *weakSelf = self;
    
        // 创建dealloc信号,当 self 或 observer 被释放时,取消监听
        RACSignal *deallocSignal = [[RACSignal
            zip:@[
                self.rac_willDeallocSignal,
                strongObserver.rac_willDeallocSignal ?: [RACSignal never]
            ]]
            doCompleted:^{
                // Forces deallocation to wait if the object variables are currently
                // being read on another thread.
                [objectLock lock];
                @onExit {
                    [objectLock unlock];
                };
            }];
        // 返回一个信号,供外部订阅
        return [[[RACSignal
            createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
                // Hold onto the lock the whole time we're setting up the KVO
                // observation, because any resurrection that might be caused by our
                // retaining below must be balanced out by the time -dealloc returns
                // (if another thread is waiting on the lock above).
                [objectLock lock];
                @onExit {
                    [objectLock unlock];
                };
    
                __strong NSObject *observer __attribute__((objc_precise_lifetime)) = weakObserver;
                __strong NSObject *self __attribute__((objc_precise_lifetime)) = weakSelf;
    
                if (self == nil) {
                    // self 为空时,sendCompleted,结束信号
                    [subscriber sendCompleted];
                    return nil;
                }
                // 调用 NSObject (RACKVOWrapper) 中的方法,按keyPath逐级添加监听
                return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
                    // 收到监听回调,调用 sendNext 触发信号
                    [subscriber sendNext:RACTuplePack(value, change)];
                }];
            }]
            takeUntil:deallocSignal]
            setNameWithFormat:@"%@ -rac_valueAndChangesForKeyPath: %@ options: %lu observer: %@", RACDescription(self), keyPath, (unsigned long)options, RACDescription(strongObserver)];
    }
    
    • NSObject (RACKVOWrapper) 对keyPath各结点进行逐级监听
    - (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block {
        NSCParameterAssert(block != nil);
        NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);
    
        keyPath = [keyPath copy];
    
        NSObject *strongObserver = weakObserver;
        // 以```.```分隔,拆分keyPath
        NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
        // keyPath是否只有一个结点
        BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);
        // keyPath 头部结点
        NSString *keyPathHead = keyPathComponents[0];
        // keyPath 头部结点以外的结点
        NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;
    
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    
        // The disposable that groups all disposal necessary to clean up the callbacks
        // added to the value of the first key path component.
        RACSerialDisposable *firstComponentSerialDisposable = [RACSerialDisposable serialDisposableWithDisposable:[RACCompoundDisposable compoundDisposable]];
        RACCompoundDisposable * (^firstComponentDisposable)(void) = ^{
            return (RACCompoundDisposable *)firstComponentSerialDisposable.disposable;
        };
    
        [disposable addDisposable:firstComponentSerialDisposable];
        // 是否需要添加 property dealloc 时的监听,用来对象被释放时,解除订阅
        BOOL shouldAddDeallocObserver = NO;
        // runtime 获取 keyPathHead 对应的属性
        objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
        if (property != NULL) {
            rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property);
            if (attributes != NULL) {
                @onExit {
                    free(attributes);
                };
                BOOL isObject = attributes->objectClass != nil || strstr(attributes->type, @encode(id)) == attributes->type;
                BOOL isProtocol = attributes->objectClass == NSClassFromString(@"Protocol");
                BOOL isBlock = strcmp(attributes->type, @encode(void(^)(void))) == 0;
                BOOL isWeak = attributes->weak;
                /**
                 判断是否需要对 property 的 dealloc 添加监听
                 是一个对象,并被弱引用,不是block,不是protocol
                 不是实例对象,不需要添加。未被弱引用,不会被自动释放,也不需要添加
                */
                shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol;
            }
        }
        // clean up the callback to the firstComponentDisposable.
        void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) {
            if (!shouldAddDeallocObserver) return;
    
            // If a key path value is the observer, commonly when a key path begins
            // with "self", we prevent deallocation triggered callbacks for any such key
            // path components. Thus, the observer's deallocation is not considered a
            // change to the key path.
            if (value == weakObserver) return;
    
            NSDictionary *change = @{
                NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
                NSKeyValueChangeNewKey: NSNull.null,
            };
    
            RACCompoundDisposable *valueDisposable = value.rac_deallocDisposable;
            RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
                block(nil, change, YES, keyPathHasOneComponent);
            }];
    
            [valueDisposable addDisposable:deallocDisposable];
            [firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{
                [valueDisposable removeDisposable:deallocDisposable];
            }]];
        };
    
        // Adds the callback block to the remaining path components on the value. Also
        // adds the logic to clean up the callbacks to the firstComponentDisposable.
        void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {
            // 递归,对 keyPathTail 各结点添加监听
            RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block];
            [firstComponentDisposable() addDisposable:observerDisposable];
        };
        // Observe only the first key path component, when the value changes c
    lean up
        // the callbacks on the old value, add callbacks to the new value and call the
        // callback block as needed.
        //
        // Note this does not use NSKeyValueObservingOptionInitial so this only
        // handles changes to the value, callbacks to the initial value must be added
        // separately.
        NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial;
        // 创建 RACKVOTrampoline,管理监听
        RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self observer:strongObserver keyPath:keyPathHead options:trampolineOptions block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
            // If this is a prior notification, clean up all the callbacks added to the
            // previous value and call the callback block. Everything else is deferred
            // until after we get the notification after the change.
            if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
                [firstComponentDisposable() dispose];
    
                if ((options & NSKeyValueObservingOptionPrior) != 0) {
                    block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent);
                }
    
                return;
            }
    
            // From here the notification is not prior.
            // 通过 KVC 取值
            NSObject *value = [trampolineTarget valueForKey:keyPathHead];
    
            // If the value has changed but is nil, there is no need to add callbacks to
            // it, just call the callback block.
            if (value == nil) {
                block(nil, change, NO, keyPathHasOneComponent);
                return;
            }
    
            // From here the notification is not prior and the value is not nil.
    
            // Create a new firstComponentDisposable while getting rid of the old one at
            // the same time, in case this is being called concurrently.
            RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]];
            [oldFirstComponentDisposable dispose];
    
            addDeallocObserverToPropertyValue(value);
    
            // If there are no further key path components, there is no need to add the
            // other callbacks, just call the callback block with the value itself.
            if (keyPathHasOneComponent) {
                block(value, change, NO, keyPathHasOneComponent);
                return;
            }
    
            // The value has changed, is not nil, and there are more key path components
            // to consider. Add the callbacks to the value for the remaining key path
            // components and call the callback block with the current value of the full
            // key path.
            // 执行 addObserverToValue block,对 keyPath 上其他结点添加监听
            addObserverToValue(value);
            block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
        }];
    
        // Stop the KVO observation when this one is disposed of.
        [disposable addDisposable:trampoline];
    
        // Add the callbacks to the initial value if needed.
        NSObject *value = [self valueForKey:keyPathHead];
        if (value != nil) {
            addDeallocObserverToPropertyValue(value);
    
            if (!keyPathHasOneComponent) {
                addObserverToValue(value);
            }
        }
    
        // Call the block with the initial value if needed.
        if ((options & NSKeyValueObservingOptionInitial) != 0) {
            id initialValue = [self valueForKeyPath:keyPath];
            NSDictionary *initialChange = @{
                NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
                NSKeyValueChangeNewKey: initialValue ?: NSNull.null,
            };
            block(initialValue, initialChange, NO, keyPathHasOneComponent);
        }
    
    
        RACCompoundDisposable *observerDisposable = strongObserver.rac_deallocDisposable;
        RACCompoundDisposable *selfDisposable = self.rac_deallocDisposable;
        // Dispose of this observation if the receiver or the observer deallocate.
        [observerDisposable addDisposable:disposable];
        [selfDisposable addDisposable:disposable];
    
        return [RACDisposable disposableWithBlock:^{
            [disposable dispose];
            [observerDisposable removeDisposable:disposable];
            [selfDisposable removeDisposable:disposable];
        }];
    }
    
    • RACKVOTrampoline 原生KVO管理
    - (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
        NSCParameterAssert(keyPath != nil);
        NSCParameterAssert(block != nil);
    
        NSObject *strongTarget = target;
        if (strongTarget == nil) return nil;
    
        self = [super init];
        // 保存相当参数
        _keyPath = [keyPath copy];
    
        _block = [block copy];
        _weakTarget = target;
        _unsafeTarget = strongTarget;
        _observer = observer;
        /**
         使用 RACKVOProxy 进行消息转发。
         self 作为context的值,用 context 保存ovserver,回调时通过 context 获取 observer,来调用对应 observer 的 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 方法。
        */
        [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
        [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
    
        [strongTarget.rac_deallocDisposable addDisposable:self];
        [self.observer.rac_deallocDisposable addDisposable:self];
    
        return self;
    }
    
    - (void)dealloc {
        [self dispose];
    }
    
    #pragma mark Observation
    // 信号结束或取消订阅时的清理
    - (void)dispose {
        NSObject *target;
        NSObject *observer;
    
        @synchronized (self) {
            _block = nil;
    
            // The target should still exist at this point, because we still need to
            // tear down its KVO observation. Therefore, we can use the unsafe
            // reference (and need to, because the weak one will have been zeroed by
            // now).
            target = self.unsafeTarget;
            observer = self.observer;
    
            _unsafeTarget = nil;
            _observer = nil;
        }
    
        [target.rac_deallocDisposable removeDisposable:self];
        [observer.rac_deallocDisposable removeDisposable:self];
        // 解除监听
        [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
        // 删除监听者
        [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
    }
    
    // 消息被转发回来后,调用 block 回调
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        if (context != (__bridge void *)self) {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
            return;
        }
    
        RACKVOBlock block;
        id observer;
        id target;
    
        @synchronized (self) {
            block = self.block;
            observer = self.observer;
            target = self.weakTarget;
        }
    
        if (block == nil || target == nil) return;
    
        block(target, observer, change);
    }
    
    • RACKVOProxy 用 KVO 统一管理
    + (instancetype)sharedProxy {
        static RACKVOProxy *proxy;
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
            proxy = [[self alloc] init];
        });
        return proxy;
    }
    
    - (instancetype)init {
        self = [super init];
    
        _queue = dispatch_queue_create("org.reactivecocoa.ReactiveObjC.RACKVOProxy", DISPATCH_QUEUE_SERIAL);
        // 创建表,保存真正的 observer
        _trampolines = [NSMapTable strongToWeakObjectsMapTable];
    
        return self;
    }
    
    - (void)addObserver:(__weak NSObject *)observer forContext:(void *)context {
        NSValue *valueContext = [NSValue valueWithPointer:context];
    
        dispatch_sync(self.queue, ^{
            [self.trampolines setObject:observer forKey:valueContext];
        });
    }
    
    - (void)removeObserver:(NSObject *)observer forContext:(void *)context {
        NSValue *valueContext = [NSValue valueWithPointer:context];
    
        dispatch_sync(self.queue, ^{
            [self.trampolines removeObjectForKey:valueContext];
        });
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        // 获取真正的 observer,调用 - (void)observeValueForKeyPath:ofObject:change:context:方法
        NSValue *valueContext = [NSValue valueWithPointer:context];
        __block NSObject *trueObserver;
    
        dispatch_sync(self.queue, ^{
            trueObserver = [self.trampolines objectForKey:valueContext];
        });
    
        if (trueObserver != nil) {
            [trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    

    相关文章

      网友评论

          本文标题:ReactiveObjC 源码阅读笔记 (RACObserve(

          本文链接:https://www.haomeiwen.com/subject/sjxkiltx.html