收錄:原文地址
上一個篇章我們對
KVO
底層有了一定了解!這一篇我們就開始分析RxSwift
對KVO
的封裝,看完這一篇,你估計也會由衷的感慨:底層源碼的思路是有相同的
RxSwift - KVO簡介
RxSwift
對KVO
的調用主要有兩種方式:
-
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
的世界必然是由序列的,第一步分析序列的創建
中間的細節流程過濾,大家自己查看源碼!我們直奔核心,馬上要上課!哈哈哈~~~~~~
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
,這里不講了,前面的流程非常簡單---直接分析重點
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
- 保存了一個閉包,我們先看里面,畢竟這里還不能執行
-
KVOObserver
這段繼承關系是非常重要的 - 繼承
_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
,完美!序列訂閱得以響應
下面還缺一個點:關于KVO
在RxSwift
的世界里面是不需要移除觀察的,下面開始解析
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流程也就是中間者模式! 移交觀察者,到達響應效果。
對于以上技術點,想要更好的探討,可以進入iOS技術圈,一起探討學習