RxSwift源码分析(16)——KVO

了解完系统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(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable 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(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable {
        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 {
    //对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 {
    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 {
    ...
    let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable

    return propertyObservable
        .flatMapLatest { (nextTarget: AnyObject?) -> Observable in
        ...
    }
}
fileprivate final class KVOObservable
    : 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 {

    weak var weakTarget: AnyObject? = target  //weak

    let propertyName = keyPathSections[0]
    let remainingPaths = Array(keyPathSections[1..

    return propertyObservable
        .flatMapLatest { (nextTarget: AnyObject?) -> Observable 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
    : ObservableType
    , KVOObservableProtocol {
    ...
    func subscribe(_ 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
    : ObservableType
    , KVOObservableProtocol {
    ...
    func subscribe(_ 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(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable {
        return KVOObservable(object: self.base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable()
    }
}

你可能感兴趣的:(RxSwift源码分析(16)——KVO)