美文网首页Rx
RxSwift源码分析(16)——KVO

RxSwift源码分析(16)——KVO

作者: 无悔zero | 来源:发表于2020-11-04 01:18 被阅读0次

    了解完系统KVO的底层原理,今天就来分析一下RxSwift的KVO源码。
    直接来看下面例子,使用起来比系统KVO方便:

    self.person.rx.observeWeakly(String.self, "name")
    .subscribe(onNext: { (change) in
        print("KVO RxSwift")
    }).disposed(by: disposeBag)
    

    对比系统KVO:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print("KVO swift")
    }
    
    deinit {
       self.person.removeObserver(self, forKeyPath: "name")       
    }
    
    1. 我们先来看创建序列的源码:
    self.person.rx.observeWeakly(String.self, "name")
    
    extension Reactive where Base: NSObject {
        public func observeWeakly<Element: RawRepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> where Element.RawValue: KVORepresentable {
            return self.observeWeakly(Element.RawValue.KVOType.self, keyPath, options: options)
                .map(Element.init)
        }
    }
    
    extension Reactive where Base: NSObject {
        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
                }
        }
    }
    
    private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable<AnyObject?> {
        //对keyPath处理了一下
        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)
        }
    }
    

    首先这里返回了observable,重点在finishWithNilWhenDealloc(target),意思是当target释放的时候会发送nil然后销毁:

    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()
        }
    }
    
    1. 最终返回的是一个KVOObservable序列(KVOObservable继承了ObservableTypeKVOObservableProtocolKVOObservableProtocol协议为序列扩展了属性能力),KVOObservable保存了targetkeyPath
    private func observeWeaklyKeyPathFor(
            _ target: NSObject,
            keyPathSections: [String],
            options: KeyValueObservingOptions
            ) -> Observable<AnyObject?> {
        ...
        let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
    
        return propertyObservable
            .flatMapLatest { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
            ...
        }
    }
    
    fileprivate final class KVOObservable<Element>
        : ObservableType
        , KVOObservableProtocol {
        typealias Element = Element?
    
        unowned var target: AnyObject
        ...
        init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
            self.target = object
            self.keyPath = keyPath
            self.options = options
            self.retainTarget = retainTarget
            if retainTarget { //参数为false 
                self.strongTarget = object
            }
        }
        ...
    }
    
    private protocol KVOObservableProtocol {
        var target: AnyObject { get }
        var keyPath: String { get }
        var retainTarget: Bool { get }
        var options: KeyValueObservingOptions { get }
    }
    
    1. 最后返回的时候还用flatMapLatest进行了容错处理,平常监听的对象都是要用strong修饰,做了容错处理就可以监听weak修饰的对象
    private func observeWeaklyKeyPathFor(
            _ target: NSObject,
            keyPathSections: [String],
            options: KeyValueObservingOptions
            ) -> Observable<AnyObject?> {
    
        weak var weakTarget: AnyObject? = target  //weak
    
        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!)
            ///判断是否为weak
        let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")
        let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
    
        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 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
                    }
        }
    }
    
    • 容错处理所需要的信息,有一个是通过runtime获取target的信息进行判断是否为weak属性,但判断只是关键字判断(嗯,没错,系统的一些错误信息也可以这样判断,进行骚操作):
    private func isWeakProperty(_ properyRuntimeInfo: String) -> Bool {
        return properyRuntimeInfo.range(of: ",W,") != nil
    }
    
    1. 序列创建好了,接着就是订阅了:
    .subscribe(onNext: { (change) in
        ...
    })
    

    根据RxSwift核心逻辑,来到KVOObservablesubscribe函数,这里创建了KVOObserverKVOObserver又继承了_RXKVOObserverDisposable协议,而_RXKVOObserver是一个OC类),在初始化时故意持有了自己造成循环引用,为了让监听能保持下去

    fileprivate final class KVOObservable<Element>
        : ObservableType
        , KVOObservableProtocol {
        ...
        func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element? {
            let observer = KVOObserver(parent: self) { value in
                ...
            }
    
            return Disposables.create(with: observer.dispose)
        }
    
    }
    
    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  //循环引用
        }
        ...
    }
    
    @interface _RXKVOObserver ()
    
    @property (nonatomic, unsafe_unretained) id            target;//相当于unowned
    @property (nonatomic, strong           ) id            retainedTarget;
    @property (nonatomic, copy             ) NSString     *keyPath;
    @property (nonatomic, copy             ) void (^callback)(id);
    
    @end
    
    @implementation _RXKVOObserver
    
    -(instancetype)initWithTarget:(id)target
                     retainTarget:(BOOL)retainTarget
                          keyPath:(NSString*)keyPath
                          options:(NSKeyValueObservingOptions)options
                         callback:(void (^)(id))callback {
        ...
        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
    

    原来在这里它实现了系统KVO的调用,清晰明了,而且不是VC进行观察而是_RXKVOObserver,这样的操作叫它观察者移交targetkeyPath就是一路传递过来的personname

    1. 当监听到name发生变化时,便会通过callback回调出去,然后进行发送:
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        @synchronized(self) {
            self.callback(change[NSKeyValueChangeNewKey]);
        }
    }
    
    fileprivate final class KVOObservable<Element>
        : ObservableType
        , KVOObservableProtocol {
        ...
        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)
        }
    
    }
    

    根据RxSwift核心逻辑,最终来到外面的响应闭包:

    .subscribe(onNext: { (change) in
        print("KVO RxSwift")
    })
    
    1. 完成监听流程,接着当序列销毁的时候,根据之前了解的销毁流程,会来到KVOObserverdispose函数,然后执行super.dispose()
    fileprivate final class KVOObserver
        : _RXKVOObserver
        , Disposable {
        ...
        override func dispose() {
            super.dispose()
            self.retainSelf = nil  //解开循环引用
        }
        ...
    }
    

    然后来到_RXKVOObserverdispose,移除监听:

    -(void)dispose {
        [self.target removeObserver:self forKeyPath:self.keyPath context:nil];
        self.target = nil;
        self.retainedTarget = nil;
    }
    

    其实内部监听写的代码不多,更多的是上层的处理。

    补充

    除了rx.observeWeakly,还有一个创建监听序列的方法:

    self.person.rx.observe(String.self, "name").subscribe(onNext: { (change) in
            print("不常用")
    }).disposed(by: disposeBag)
    

    这个方法直接返回了KVOObservable序列,少了很多处理,也就是简单封装了一下KVO,而且retainTarget传递的是true,强引用了object,为的是不让观察目标释放(毕竟不像rx.observeWeakly调用finishWithNilWhenDealloc(target)对观察目标的释放进行了处理)

    extension Reactive where Base: NSObject {
    
        public func observe<Element>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable<Element?> {
            return KVOObservable(object: self.base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable()
        }
    }
    

    相关文章

      网友评论

        本文标题:RxSwift源码分析(16)——KVO

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