RxSwift-KVO

一、Swift-KVO

  • 步骤一、添加观察
    func swiftKVO() {
        person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
    }
  • 步骤二、观察回调
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print(change!)
    }
  • 步骤三、移除观察
    deinit {
        person.removeObserver(self, forKeyPath: "name")
    }
  • 注意:监听的属性前 必须 加上 @objc dynamic
import UIKit

class Person: NSObject {
    @objc dynamic var name: String = "dyz"
}

二、RxSwift-KVO

  • 2.1、observe
        self.person.rx.observe(String.self, "name").subscribe(onNext: { (value) in
            print(value!)
        }).disposed(by: disposeBag)
  • 2.2、observeWeakly
        self.person.rx.observeWeakly(String.self, "name").subscribe(onNext: { (value) in
            print(value!)
        })
        .disposed(by: disposeBag)

分析 observeWeakly

#if !DISABLE_SWIZZLING && !os(Linux)
// KVO
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
            }
    }
}
#endif
  • target:被观察者Person
    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)
        }
    }
  • 点击finishWithNilWhenDealloc
    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()
        }
    }
  • 点击observeWeaklyKeyPathFor来到下面代码
  • 点击KVOObservable
    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
                }
        }
    }
  • KVOObservable 实现了KVOObservableProtocol协议,拥有了target、keyPath、retainTarget、options等属性
  • 外界调用subscribe(onNext:...),RxSwift 核心逻辑,必然会来到下面的subscribe方法
  • subscribe中初始化KVOObserver观察者和保存闭包(闭包的回调是在KVO收到响应的时候)
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)
    }

}

fileprivate extension KeyValueObservingOptions {
    var nsOptions: NSKeyValueObservingOptions {
        var result: UInt = 0
        if self.contains(.new) {
            result |= NSKeyValueObservingOptions.new.rawValue
        }
        if self.contains(.initial) {
            result |= NSKeyValueObservingOptions.initial.rawValue
        }
        
        return NSKeyValueObservingOptions(rawValue: result)
    }
}
private protocol KVOObservableProtocol {
    var target: AnyObject { get }
    var keyPath: String { get }
    var retainTarget: Bool { get }
    var options: KeyValueObservingOptions { get }
}
  • 点击KVOObserver,来到KVOObserver类,它继承_RXKVOObserver类
  • 调用父类_RXKVOObserver的初始化方法,把值和闭包都传给父类
  • dispose方法,会调用父类_RXKVOObserver的dispose方法,从而移除观察
fileprivate final class KVOObserver
    : _RXKVOObserver
    , Disposable {
    typealias Callback = (Any?) -> Void

    var retainSelf: KVOObserver?

    init(parent: KVOObservableProtocol, callback: @escaping Callback) {
        #if TRACE_RESOURCES
            _ = Resources.incrementTotal()
        #endif

        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
    }

    deinit {
        #if TRACE_RESOURCES
            _ = Resources.decrementTotal()
        #endif
    }
}
  • _RXKVOObserver类是一个OC类
@interface _RXKVOObserver : NSObject

-(instancetype)initWithTarget:(id)target
                 retainTarget:(BOOL)retainTarget
                      keyPath:(NSString*)keyPath
                      options:(NSKeyValueObservingOptions)options
                     callback:(void (^)(id))callback;

-(void)dispose;

@end
  • 添加观察:观察者移交[self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];
  • 观察回调:-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {},执行保存的闭包
  • 移除观察:[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
@interface _RXKVOObserver ()

@property (nonatomic, unsafe_unretained) id            target;
@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 = [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

重点:RX-SwiftKVO其实是封装的是OC的KVO,Swift的封装的也是OC的KVO

你可能感兴趣的:(RxSwift-KVO)