RxSwift(KVO底层探索)

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(_ 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
        }
}
  • 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 {
        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 {

        weak var weakTarget: AnyObject? = target

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

        // KVO recursion for value changes
        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 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
    : 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: 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 {
                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底层探索))