RxSwift(9)— KVO底層探索(下)

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!編程


RxSwift 目錄直通車 --- 和諧學習,不急不躁!swift


上面一篇章咱們對KVO底層有了必定了解!這一篇咱們就開始分析RxSwiftKVO的封裝,看完這一篇,你估計也會由衷的感慨:底層源碼的思路是有相同的閉包

RxSwift - KVO簡介

RxSwiftKVO的調用主要有兩種方式:ide

  • rx.observe:更加高效,由於它是一個 KVO 機制的簡單封裝。
  • rx.observeWeakly : 執行效率要低一些,由於它要處理對象的釋放防止弱引用(對象的 dealloc 關係)。

應用場景:函數

  • 在可使用 rx.observe 的地方均可以使用 rx.observeWeakly
  • 使用 rx.observe 時路徑只能包括 strong 屬性,不然就會有系統崩潰的風險。而 rx.observeWeakly 能夠用在 weak 屬性上。
self.person.rx.observeWeakly(String.self, "name")
            .subscribe(onNext: { (change) in
                print("observeWeakly訂閱到了KVO:\(String(describing: change))")
            }).disposed(by: disposeBag)
複製代碼

使用起來很是簡單,可讀性高,免去傳統KVO帶來的噁心!下面也粘貼出代碼對比一下源碼分析

// 1: 添加觀察
person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
// 2: 觀察響應回調
override func observeValue(forKeyPath keyPath:, of object:, change: , context:){} // 3: 移除觀察 person.removeObserver(self, forKeyPath: "name")
複製代碼

RxSwift - KVO底層探索

首先分析在RxSwift 的世界必然是由序列的,第一步分析序列的建立post

self.person.rx.observeWeakly(String.self, "name")
複製代碼

中間的細節流程過濾,你們本身查看源碼!咱們直奔核心,立刻要上課!哈哈哈~~~~~~學習

let observable = observeWeaklyKeyPathFor(target, keyPathSections: components, options: options)
    .finishWithNilWhenDealloc(target)
複製代碼
  • observeWeaklyKeyPathFor內部建立序列
  • finishWithNilWhenDealloc 針對提早釋放的變量的容錯,若是對象釋放,也就沒有觀察的必要,寫的很錯,畢竟可以觀察weak修飾對象
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>
複製代碼
  • 這段代碼主要針對觀察的keyPath進行處理分析
  • KVOObservable 就是咱們的KVO觀察的序列,這個對象繼承ObservableType,讓其具有序列的特性。實現KVOObservableProtocol協議,拓展幾個協議屬性,常規面向協議編程的思路
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
    }
}
複製代碼
  • 這段代碼,想必你們看完上一篇文章以後很是容易理解,就是咱們KVO信息保存者
  • 初始化完畢就是外界flatMapLatest的封裝容錯

序列已經建立完畢,下面開始分析訂閱,響應發送

常規訂閱,提供給內部:AnonymousObserver,這裏不講了,前面的流程很是簡單---直接分析重點ui

func subscribe(_ observer: Observer) -> Disposable {
    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)
}
複製代碼
  • 核心重點類KVOObserver
  • 保存了一個閉包,咱們先看裏面,畢竟這裏還不能執行
class KVOObserver: _RXKVOObserver, Disposable 複製代碼
  • 這段繼承關係是很是重要的
  • 繼承_RXKVOObserver,咱們查看內部,個人天啊!居然是一個OC類
  • 實現Disposable協議,具有銷燬的能力,用來幹嗎,等會講解
-(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;
}
複製代碼
  • 這裏面針對外界的一些KVO信息處理保存,callback回調的保存,函數式思想
  • [self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];這段代碼是比較騷,核心邏輯:觀察者移交,咱們不在是VC觀察,使咱們內部類!
  • 觀察的keypath有了變化,必然胡響應下面的方法
-(void)observeValueForKeyPath: ofObject: change: context: {
    @synchronized(self) {
        self.callback(change[NSKeyValueChangeNewKey]);
    }
}
複製代碼
  • 重點就是以前保存的回到函數調用self.callback(change[NSKeyValueChangeNewKey]),那麼咱們的流程就會流到以前的對象初始化時候的閉包
let observer = KVOObserver(parent: self) { value in
    if value as? NSNull != nil {
        observer.on(.next(nil))
        return
    }
    observer.on(.next(value as? Element))
}
複製代碼
  • 咱們觀察者直接進行了發送響應,這裏的value值就是KVO回調的change,完美!序列訂閱得以響應

下面還缺一個點:關於KVORxSwift的世界裏面是不須要移除觀察的,下面開始解析spa

override func dispose() {
    super.dispose()
    self.retainSelf = nil
}
複製代碼
  • 這個dispose的流程是很是簡單了,前面咱們也有相關分析
  • 核心就是調用了 super.dispose()
-(void)dispose {
    [self.target removeObserver:self forKeyPath:self.keyPath context:nil];
    self.target = nil;
    self.retainedTarget = nil;
}
複製代碼
  • 只要咱們的序列銷燬或者訂閱關係的銷燬的時候就會自動調用dispose
  • 完美看到觀察的移除!

縱觀RxSwift的KVO流程也就是中間者模式! 移交觀察者,到達響應效果。

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!

相關文章
相關標籤/搜索