美文网首页
RxSwift(KVO底层探索)

RxSwift(KVO底层探索)

作者: Maji1 | 来源:发表于2019-11-20 15:23 被阅读0次

    KVO底层探索请参考文章 KVO底层探索

    RxSwift对KVO的调用主要有两种方式:

    • rx.observe()

     1、对KVO的封装相对简单,高效。
     2、路径不能包含weak属性,否则有可能会造成崩溃

    • rx.observeWeakly()

     1、对KVO的封装相对复杂一些,处理了对象的弱引用防止释放
     2、可以用在weak属性上
     3、使用rx.observe()的地方都可以使用rx.observeWeakly()

    下面贴出使用代码 代码-001

    //代码-001
    self.person.rx.observeWeakly(String.self, "name")
                .subscribe(onNext: { (value) in
                    print("KVO:\(String(describing: value))")
                })
                .disposed(by: disposeBag)
    

    一、.observeWeakly()

    首先点击进入.observeWeakly() 方法,来到Reactive结构体的扩展方法里面 代码-002

    //代码-002
    public func observeWeakly<Element>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> {
            return observeWeaklyKeyPathFor(self.base, keyPath: keyPath, options: options)
                .map { n in
                    return n as? Element
            }
    }
    
    • self.base就是我们的person对象。
    • keyPath就是name
    • options的值是[.new, .initial]

    点击observeWeaklyKeyPathFor (self.base, keyPath: keyPath, options: options)方法 代码-003

    //代码-003
     private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable<AnyObject?> {
            let components = keyPath.components(separatedBy: ".").filter { $0 != "self" }
    
            let observable = observeWeaklyKeyPathFor(target, keyPathSections: components, options: options)
                .finishWithNilWhenDealloc(target)
    
            if !options.isDisjoint(with: .initial) {
                return observable
            }
            else {
                return observable
                    .skip(1)
            }
    }
    
    • 1、将keyPath解析放到components数组里
    • 2、bserveWeaklyKeyPathFor(target, keyPathSections: components, options: options) .finishWithNilWhenDealloc(target)创建observable序列
    • 3、options.isDisjoint(with: .initial) 判断是否存在.initial值,存在返回false

    下面我们来重点看一下第二部如何创建observable序列,点击进入 代码-004

    //代码-004
    private func observeWeaklyKeyPathFor(
            _ target: NSObject,
            keyPathSections: [String],
            options: KeyValueObservingOptions
            ) -> Observable<AnyObject?> {
    
            weak var weakTarget: AnyObject? = target
    
            let propertyName = keyPathSections[0]
            let remainingPaths = Array(keyPathSections[1..<keyPathSections.count])
    
            let property = class_getProperty(object_getClass(target), propertyName)
            if property == nil {
                return Observable.error(RxCocoaError.invalidPropertyName(object: target, propertyName: propertyName))
            }
            let propertyAttributes = property_getAttributes(property!)
    
            // should dealloc hook be in place if week property, or just create strong reference because it doesn't matter
            let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")
            let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
    
            // KVO recursion for value changes
            return propertyObservable
                .flatMapLatest { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
                    if nextTarget == nil {
                        return Observable.just(nil)
                    }
                    let nextObject = nextTarget! as? NSObject
    
                    let strongTarget: AnyObject? = weakTarget
    
                    if nextObject == nil {
                        return Observable.error(RxCocoaError.invalidObjectOnKeyPath(object: nextTarget!, sourceObject: strongTarget ?? NSNull(), propertyName: propertyName))
                    }
    
                    // if target is alive, then send change
                    // if it's deallocated, don't send anything
                    if strongTarget == nil {
                        return Observable.empty()
                    }
    
                    let nextElementsObservable = keyPathSections.count == 1
                        ? Observable.just(nextTarget)
                        : observeWeaklyKeyPathFor(nextObject!, keyPathSections: remainingPaths, options: options)
                    
                    if isWeak {
                        return nextElementsObservable
                            .finishWithNilWhenDealloc(nextObject!)
                    }
                    else {
                        return nextElementsObservable
                    }
            }
        }
    
    • 1、首先弱引用weakTarget
    • 2、let property = class_getProperty(object_getClass(target), propertyName)获取target中对应keyPath的属性
    • 3、let propertyAttributes = property_getAttributes(property!)获取属性的Attributes
    • 4、let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")判断是否是弱引用
    • 5、创建KVOObservable类型的序列propertyObservable
    • 6、返回propertyObservable序列

    我们看下创建KVOObservable类型的序列propertyObservable代码 代码-005

    //代码-005
    fileprivate final class KVOObservable<Element>
        : ObservableType
        , KVOObservableProtocol {
        typealias Element = Element?
    
        unowned var target: AnyObject
        var strongTarget: AnyObject?
    
        var keyPath: String
        var options: KeyValueObservingOptions
        var retainTarget: Bool
    
        init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
            self.target = object
            self.keyPath = keyPath
            self.options = options
            self.retainTarget = retainTarget
            if retainTarget {
                self.strongTarget = object
            }
        }
    
        func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element? {
            let observer = KVOObserver(parent: self) { value in
                if value as? NSNull != nil {
                    observer.on(.next(nil))
                    return
                }
                observer.on(.next(value as? Element))
            }
    
            return Disposables.create(with: observer.dispose)
        }
    
    }
    
    • 1、target的持有使用unowned修饰,弱引用,一旦被释放不会被置为nil,再调用就会崩溃,相比weak来说性能更高。
    • 2、该类内实现了subscribe方法,序列的常规操作。

    看一下 代码-003 中的.finishWithNilWhenDealloc(target)方法实现,点击进入 代码-006

    //代码-006
    fileprivate extension ObservableType where Element == AnyObject? {
            func finishWithNilWhenDealloc(_ target: NSObject)
                -> Observable<AnyObject?> {
                    let deallocating = target.rx.deallocating
    
                    return deallocating
                        .map { _ in
                            return Observable.just(nil)
                        }
                        .startWith(self.asObservable())
                        .switchLatest()
            }
    }
    

    我们先按字面意思理解一下,销毁时将target设置为nil

    二、.subscribe({ })

    对RxSwift有了一定的了解,这个地方很明显,我们直接查看 代码-005 内的方法实现:

    • 1、 创建KVOObserver类型的监听者observer
    • 2、返回Disposables销毁者

    继续查看KVOObserver类内的代码 代码-007

    //代码-007
    fileprivate final class KVOObserver
        : _RXKVOObserver
        , Disposable {
        typealias Callback = (Any?) -> Void
    
        var retainSelf: KVOObserver?
    
        init(parent: KVOObservableProtocol, callback: @escaping Callback) {
            super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)
            self.retainSelf = self
        }
    
        override func dispose() {
            super.dispose()
            self.retainSelf = nil
        }
    }
    
    • 1、KVOObserver继承之_RXKVOObserver
    • 2、遵守Disposable协议,目的是自我销毁

    查看_RXKVOObserver类内的代码 代码-008

    @implementation _RXKVOObserver
    
    -(instancetype)initWithTarget:(id)target
                     retainTarget:(BOOL)retainTarget
                          keyPath:(NSString*)keyPath
                          options:(NSKeyValueObservingOptions)options
                         callback:(void (^)(id))callback {
        self = [super init];
        if (!self) return nil;
        
        self.target = target;
        if (retainTarget) {
            self.retainedTarget = target;
        }
        self.keyPath = keyPath;
        self.callback = callback;
        // 观察者移交 - 中间类
        [self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];
        
        return self;
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        @synchronized(self) {
            self.callback(change[NSKeyValueChangeNewKey]);
        }
    }
    
    -(void)dispose {
        [self.target removeObserver:self forKeyPath:self.keyPath context:nil];
        self.target = nil;
        self.retainedTarget = nil;
    }
    
    @end
    

    发现是OC代码,一共就实现了三个方法,这三个方法做了三件事:1、 添加观察 2、观察响应回调 3、移除观察。这就是KVO的三部曲呀,典型的中介者模式。

    因为我们的options包含了.initial值,所以初始化的时候会执行一次self.callback(change[NSKeyValueChangeNewKey]);方法。
    这里的callBack就是我们KVOObserver({ })后面的闭包 代码-005observer.on(.next(value as? Element))执行,所以序列响应。

    只要我们的序列销毁或者订阅关系的销毁的时候就会自动调用dispose

    相关文章

      网友评论

          本文标题:RxSwift(KVO底层探索)

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