簡述
最近老大給了個新專案,我打算用Swift寫.原來OC用的RAC,換到Swift自然框架也想試試新的,就用了RXSwift,對於這兩個框架,我都是會用,但不解其中的原理,正好最近需求沒下來,就研究了研究RXSwif,把自己的收穫分享一下,文中要有不準確的地方還望大家多多指正~
關於RXSwift是什麼和怎麼用我就不廢話了,網上資源很多,本文先從Observable實現原理入手,旨在以小見大,後面的Single
什麼的自然舉一反三~
使用Demo
下面是一段簡單使用Observable的程式碼
let numbers: Observable<Int> = Observable.create { observer -> Disposable in
observer.onNext(0)
observer.onNext(1)
observer.onCompleted()
return Disposables.create {
}
}
numbers.subscribe{
print($0)
}
複製程式碼
demo實現的效果其實就是 將上一段閉包中輸入的 產生的事件(0,1,Completed),在下一段閉包中提取出來. 這樣就將 事件的產生 和 事件的處理 分開. 本文也就是分析這個效果怎麼實現的
主要類
AnonymousObservable
匿名可觀察者,儲存產生事件的閉包 和啟用處理事件閉包的入口
AnyObserver
任意觀察者,用於儲存事件 和 輸出事件
AnonymousObserver
匿名觀察者,用於儲存 處理事件的閉包
AnonymousObservableSink
將可觀察者 和 觀察者 連結,實現事件的傳遞
ObserverType,ObservableType..協議
協議,將上面所有內容都包裹起來,將它們加以限制,便於有效的溝通~
Event
事件本身,是列舉,有 Error,Complete,Element(元素)
實現過程
儲存
首先要說的是 ObserverType 定義的一些內容
associatedtype E
func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
複製程式碼
E:為本次事件流中定義一個確定的型別,保證 產生的和處理的元素型別相同,否則無法傳遞
create方法
Observable<Int>.create { observer -> Disposable in ....}
對於Observable
,它是一個抽象類,我們在實際使用中並不能使用它,在協議中有預設的實現
extension ObservableType {
public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> {
return AnonymousObservable(subscribe)
}
}
複製程式碼
所以此處建立的是 AnonymousObservable
物件,我先稱其為A1,A1將事件產生的閉包持有, 閉包中產生的事件 輸入到AnyObserver
結構體中.閉包我們成為A2 這樣 儲存部分就好了~~
啟用
啟用 我們通過呼叫A1的訂閱方法subscribe
(也是協議中限定的方法),接下來看方法中的實現~
因為Observable
是抽象類,所以這裡也是協議預設的實現
public func subscribe(_ on: @escaping (Event<E>) -> Void)
-> Disposable {
let observer = AnonymousObserver { e in
on(e)
}
return self.asObservable().subscribe(observer)
}
複製程式碼
在這裡就分兩步了,一是觀察者的實現,而是事件的傳遞
觀察者
在這裡很簡單,也就是建立AnonymousObserver
匿名觀察者物件B1,B1將事件處理閉包持有,閉包我們成為B2
傳遞
首先是asObservable()
方法,因為 B1間接繼承自Observable
,所以也就是return self
,應該是在處理其他型別的可觀察物用到,在後續 如果碰到我會補充~
然後就是對A1的 另一個訂閱方法(過載),將B1作為引數傳入 細枝末節先不說,先把握主幹~
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
if !CurrentThreadScheduler.isScheduleRequired {
//第一步
let disposer = SinkDisposer()
//第二步
let sinkAndSubscription = run(observer, cancel: disposer)
//第三步
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
}
//else先不說~
else {
return CurrentThreadScheduler.instance.schedule(()) { _ in
let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
}
}
}
複製程式碼
第一步
SinkDisposer
物件是關於 傳遞結束後,處理資源回收的物件,叫它C1,用來處理 A1create閉包返回的disposer閉包的~
第二步
呼叫了run
方法,將B1物件傳入
override func run<O : ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
//2.1
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
//2.2
let subscription = sink.run(self)
//2.3
return (sink: sink, subscription: subscription)
}
複製程式碼
2.1步
建立AnonymousObservableSink物件,我稱它D1,它也是將B1物件和C1物件持有
2.2步
呼叫D1物件的run
方法,將A1自身傳入
func run(_ parent: Parent) -> Disposable {
return parent._subscribeHandler(AnyObserver(self))
}
複製程式碼
在該方法中,就是將A1物件的A2閉包 呼叫,將D1物件化為AnyObserver
結構體作為A2引數傳入~
然後我們看 D1物件 若何轉換的
//結構體方法
public init<O : ObserverType>(_ observer: O) where O.E == Element {
self.observer = observer.on
}
複製程式碼
在這裡結構體 將 D1持有的B1物件的on方法 作為屬性持有~,將結構體成為E1
再來看E1的onNext....
方法
extension ObserverType {
//YSD
/// Convenience method equivalent to `on(.next(element: E))`
///
/// - parameter element: Next element to send to observer(s)
public func onNext(_ element: E) {
on(.next(element))
}
/// Convenience method equivalent to `on(.completed)`
public func onCompleted() {
on(.completed)
}
/// Convenience method equivalent to `on(.error(Swift.Error))`
/// - parameter error: Swift.Error to send to observer(s)
public func onError(_ error: Swift.Error) {
on(.error(error))
}
}
複製程式碼
對應的其實是呼叫 B1的on
方法~~
func on(_ event: Event<E>) {
switch event {
case .next:
if _isStopped == 0 {
onCore(event)
}
case .error, .completed:
if AtomicCompareAndSwap(0, 1, &_isStopped) {
onCore(event)
}
}
}
複製程式碼
對應的B1的onCore
方法
override func onCore(_ event: Event<Element>) {
return _eventHandler(event)
}
複製程式碼
也就是將 E1從A2接收的事件 傳入B2中,最終實現內容的傳遞~~ 然後再將A1中釋放資源的閉包返回~
2.3
將D1和disposable閉包 作為元組返回~
第三步
C1接收元組引數,呼叫setSinkAndSubscription
方法~,然後將SinkDisposer物件返回,讓使用者選擇是否釋放~
圖示
文字太抽象,畫個圖吧~ 畫的有點醜(๑•ᴗ•๑)~
可以看到 A1 在這個過程中只持有了A2, 不會導致記憶體洩露~ 當然如果你dispose 使用不當 肯定有洩漏的~ 親測(๑•ᴗ•๑)~
細枝末節
1
訂閱2中的if !CurrentThreadScheduler.isScheduleRequired
內容是這樣的~
public static fileprivate(set) var isScheduleRequired: Bool {
get {
//獲取該指示值
return pthread_getspecific(CurrentThreadScheduler.isScheduleRequiredKey) == nil
}
set(isScheduleRequired) {
// 成功返回0 true設定no no設定為 true
if pthread_setspecific(CurrentThreadScheduler.isScheduleRequiredKey, isScheduleRequired ? nil : scheduleInProgressSentinel) != 0 {
rxFatalError("pthread_setspecific failed")
}
}
}
private static var isScheduleRequiredKey: pthread_key_t = { () -> pthread_key_t in
//YSD
//https://onevcat.com/2015/01/swift-pointer/
//可變指標 pthread_key_t型別 分配空間
let key = UnsafeMutablePointer<pthread_key_t>.allocate(capacity: 1)
defer {
key.deallocate(capacity: 1)
}
//建立執行緒安全的變數
guard pthread_key_create(key, nil) == 0 else {
rxFatalError("isScheduleRequired key creation failed")
}
return key.pointee
}()
複製程式碼
這裡應該是為了保護,RXSwift在多執行緒操作下的資料安全~ 在本次事件流中只使用了get方法,並沒使用set~,所以具體效果我不清楚~,以後碰到了 我在補充上吧~
SinkDisposer
就是釋放資源部分~
fileprivate enum DisposeState: UInt32 {
case disposed = 1
case sinkAndSubscriptionSet = 2
}
// Jeej, swift API consistency rules
fileprivate enum DisposeStateInt32: Int32 {
case disposed = 1
case sinkAndSubscriptionSet = 2
}
private var _state: AtomicInt = 0
private var _sink: Disposable? = nil
private var _subscription: Disposable? = nil
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
_sink = sink
_subscription = subscription
let previousState = AtomicOr(DisposeState.sinkAndSubscriptionSet.rawValue, &_state)
if (previousState & DisposeStateInt32.sinkAndSubscriptionSet.rawValue) != 0 {
rxFatalError("Sink and subscription were already set")
}
if (previousState & DisposeStateInt32.disposed.rawValue) != 0 {
sink.dispose()
subscription.dispose()
_sink = nil
_subscription = nil
}
}
func dispose() {
let previousState = AtomicOr(DisposeState.disposed.rawValue, &_state)
if (previousState & DisposeStateInt32.disposed.rawValue) != 0 {
return
}
if (previousState & DisposeStateInt32.sinkAndSubscriptionSet.rawValue) != 0 {
guard let sink = _sink else {
rxFatalError("Sink not set")
}
guard let subscription = _subscription else {
rxFatalError("Subscription not set")
}
sink.dispose()
subscription.dispose()
_sink = nil
_subscription = nil
}
}
複製程式碼
從輸出崩潰提示哪裡就可以得知~ 這裡是為了防止dispose的多次呼叫~ 因為在整個事件流中,dipose閉包 可能是 產生Complete,Error或者使用者手動呼叫的~
AtomicOr
方法其實呼叫的是OSAtomicOr32OrigBarrier(A,&B)
該函式會將兩個變數 執行緒安全的 按位或運算返回結果, 併為後者賦值=前者~ B=A
未呼叫dipose時 邏輯與運算 state = 2 previousState = 0 兩個條件都不成立~ 所以此時是使用者要手動dispose
之前呼叫過 也就是發生complete 或 Error(在上面的程式碼中也有保證,兩者只發生一起~),則 state = 1當呼叫setSinkAndSubscription方法時 邏輯與運算 state = 2 previousState = 1 則第一個條件不成立 第二個成立~ 釋放資源
當多次Complete時,則只會dipose一次~
當在外界多次呼叫時 則state = 2 previousState = 1 則第一個條件成立 崩潰~
當然這裡實現這種效果的方案有很多種~ RSSwift的方案比較有逼格吧~
總結
看完這些原始碼,我的感覺是RXSwift對 設計模式 貫徹的很徹底~ 在時間富裕的情況下自己寫的專案要向他靠攏,增強專案的延展性,這樣專案經理讓加啥也不會太頭疼了~~