RxSwift學習重點整理

RxSwift學習重點:

不可忘記的前提:

  • 事件是在哪一條thread上執行(ex: main thread or background thread)
  • 物件的生命週期(i.e Observable/Observer的生命週期)
  • 效能
  • 使用的記憶體控管

RxSwift好處:

  • 運用function programming方式,解決code過於分散等問題,讓程式碼好維護(p.s. RxSwift拿去跟Target-action/Closure/Delegate相比)
  • 呼叫update UI的code永遠需要nested在asynchronous action內的問題 (p.s. KVO, Swift的didSet也有解決這個問圖)
  • 解決asynchronous action之間有Dependency時,都會需要nested

RxSwfit達成上述好處的實作概念:

  • 透過抽象化asynchronous action,包成function programming的形式讓開發者使用

RxSwift正確用法的抽象概念:

  • 確保「訂閱/與訂閱物件的生命週期」能被預期(i.e. 知道何時生成/銷毀)
  • 妥善運用compound operator(例如: combineLatest/zip、flatMap vs flatMapLatest、distinctUntilChanged、……),知道其差別與何時使用

判斷工程師對RxSwift熟練的程度:

  1. 會用RxSwift完成功能
  2. 會區分RxSwift和Target-action/Closure/Delegate的差別
  3. 了解如何妥善運用RxSwift,而不是一些可以用基本data structure(ex: Array、Dictionary……)的地方,也不自覺得使用RxSwift
  4. 了解RxSwift比較複雜的operator且能說出類似operator的差別與何時使用
  5. 會管控RxSwift的訂閱生命週期與Observable和Observer是在哪個thread上執行
  6. 有辦法運用RxSwift達成MVVM architecture(p.s. 達成Decouple UI和ViewModel、UI和ViewModel和Service的關係)
  7. 能把上面整理的RxSwift重點自己講出來,且「能上機實作出來」
  8. 不僅(7)能達成,也有應用於大型系統架構的實務經驗(ex: 一萬行code及能畫出UML class diagrams,並說明運用RxSwift後,達成什麼事,有哪些地方/原則要注意)

Backpressure feature of RxJava(p.s. RxSwift doesn’t have this feature)

https://github.com/ReactiveX/RxJava/wiki/Backpressure

Ref:
https://beeth0ven.github.io/RxSwift-Chinese-Documentation/

IOS – 模擬RxSwift

class DisposeBag {
var delegate: RxSimulator?
deinit {
print("test11 DisposeBag deinit")
delegate = nil
}
}
class RxSimulator {
var action: ((Bool) -> Void)? = nil
weak var disposeBag: DisposeBag?
func createObservable(closure: ((Bool) -> Void)? = nil) -> RxSimulator {
action = closure
return self
}
func subscribe(callback: ((Bool) -> Void)? = nil) -> RxSimulator {
action = callback
return self
}
func onNext(val: Bool) {
action?(val)
}
func disposed(by disposeBag: DisposeBag) {
self.disposeBag = disposeBag
self.disposeBag?.delegate = self
}
deinit {
print("test11 RxSimulator deinit")
}
}
class ViewController: UIViewController {
var disposeBag: DisposeBag? = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
if let disposeBag = disposeBag {
let myClosure: ((Bool) -> Void)? = { input in
print("execute myClosure")
}
let observable = RxSimulator().createObservable(closure: myClosure)
observable.subscribe { result in
print("test11 In subscribe, result is: \(result)")
}.disposed(by: disposeBag)
DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
print("test11 execute observable.onNext")
observable.onNext(val: true)
}
DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
self.disposeBag = nil
}
}
}
}

RxSwift整理

RxSwift

Definition:
Use concept of Observer pattern and sequence operators, let us handle asynchronous data/event together in a declarative manner

The tools(i.e. objects) provided:

  • Observable
  • Operators
  • Subject
  • Scheduler

Observable

Definition:
The object that emits data/event asynchronously

Functions:

  • subscribe/unsubscribe
  • Manage life time

Operators

Definition:
Provide the way to handle data collection after receiving data/event from observable

Functions:

  • Creating Observables
  • Transforming Observables
  • Filtering Observables
  • Combining Observables
  • Error Handling Operators
  • Observable Utility Operators
  • Conditional and Boolean Operators
  • Mathematical and Aggregate Operators
  • Backpressure Operators
  • Connectable Observable Operators

Subject

Definition:
Acts both as an observer and as an Observable. Because it is an observer, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by reemitting them, and it can also emit new items.

Scheduler

Definition:
introduce multithreading into your cascade of Observable operators, you can do so by instructing those operators (or particular Observables) to operate on particular Schedulers.

Operators for specifying which thread:

  • SubscribeOn (p.s. specifying a different Scheduler on which the Observable should operate)
  • ObserveOn (p.s. specifies a different Scheduler that the Observable will use to send notifications to its observers.)

RxSwift使用

以下資料參考自Ref,這裡僅作個人學習整理

Rx的一個核心觀念就是observable(或叫sequence ),口訣就是,Everything is a SEQUENCE,大意就是在Rx的世界,都是由observable構成。

Observable的生命週期:

  1. 使用.subscribe來訂閱Observable
  2. 當訂閱者收到Observable發出的.next、.error、.completed事件時,會依據我們定義好的程式執行
  3. Dispose
    Note:
    當我們subscribe()時,就會產生一個Disposable,當今天deinit時,Observable卻還沒結束,這時裝在DisposeBag中的所有Disposable就會執行dispose(),藉此來釋放資源

建立Observable方式:

  • .of
  • .interval
  • .just
  • .from
  • .never (p.s. 不會發送也不會結束的Observable)
  • .empty (p.s. 只會發送.completed的Observable)
  • .error (p.s. 只會發送.error的Observable,在測試的時候比較常用到。)
  • .create (p.s. 提供你客製化Observable方式)

Subject:
他同時是Observable跟Observer
Note:
疑問: 為什麼需要「Subject」? 單純是為了方便簡化code??

Subject種類?:

  • PublishSubject (p.s. 開始是空的,只會發送新的元素給訂閱者)
  • BehaviorSubject (p.s. 它定義是『開始是預設值,發送目前的最後一個值給訂閱者』,也就是說你不管什麼時候訂閱,都會有元素可以收到(至少有預設值)。)
  • ReplaySubject (p.s. 開始時給訂一個暫存大小(buffer size),發送時會將最後的n個元素存進暫存,並將暫存的元素發給訂閱者)
  • AsyncSubject(這很少用到,就不提了)
  • PublishRelay (p.s. 只接受.next事件,不接受.error或.completed. Note: 從source code來看,PublishRelay其實就是PublishSubject再包一層)
  • BehaviorRelay(p.s. 只接受.next事件,不接受.error或.completed. Note: 從source code來看,BehaviorRelay其實就是BehaviorSubject再包一層)

注意事項:
你會發現,Subject在同個class或是不同class被到處被onNext(),Relay被到處.accept(),這樣我們又回到Imperative思維,並且在Imperative上包一層的感覺,反而更不舒服,寫久了會很亂,也會常常出錯。
EX:
Observable
.subscribe(onNext: {
observerA.onNext(…)
observerB.onNext(…)
observerC.onNext(…)
})
.disposed(by: disposeBag)

#

Filtering Observables:
使用範例:
Observable.of(1, 2, 3, 4, 5)
.debug(“A")
.filter { $0 % 2 == 1 }
.debug(“B")
.subscribe()
.disposed(by: disposeBag)

說明:
只有滿足closure內條件的元素才會被執行

Skip Observables:
「skip」使用範例:
Observable.of(1, 2, 3, 4, 5)
.skip(2)
.debug(“B")
.subscribe()
.disposed(by: disposeBag)

說明:
略過前兩個元素(i.e. 1, 2)

「skipWhile」使用範例:
Observable.of(1, 3, 5, 6, 7)
.skipWhile { $0 % 2 == 1 }
.debug(“B")
.subscribe()
.disposed(by: disposeBag)

說明:
略過符合條件的元素,直到遇到不符合條件的元素(即 false),就停止略過
p.s. 範例中的1, 3, 5, 6, 7,只有6和7會執行

「skipUntil」使用範例:
let subject = PublishSubject()
let trigger = PublishSubject()
subject
.skipUntil(trigger)
.debug(“B")
.subscribe()
.disposed(by: disposeBag)
subject.onNext(“1″)
subject.onNext(“2″)
trigger.onNext(())
subject.onNext(“3″)
subject.onNext(“4″)

說明:
定義『略過元素,直到另一個Observable發送元素,就停止略過』,跟前面兩種相比,前面兩種是靜態的設定過濾條件,skipUntil則是可以基於另一個Observable 去動態過濾元素。

Take Observables:
take跟skip就是相反的存在,前者是取的n個元素,後者是略過n個元素,同樣的,它也有takeWhile跟takeUntil。

DistinctUntilChanged:
定義『排除重複的元素,直到不是重複時,才會發出』,比如下方範例,當true轉false時才會發送元素
使用範例:
Observable.of(true, true, false, false, true, false)
.distinctUntilChanged()
.debug(“B")
.subscribe()
.disposed(by: disposeBag)
執行結果:
B -> subscribed
B -> Event next(true)
B -> Event next(false)
B -> Event next(true)
B -> Event next(false)
B -> Event completed
B -> isDisposed

Getting started with RxSwift

以下資料參考自Ref,這裡僅作個人學習整理

  • Definition of ReactiveX
  • Advantage of ReactiveX
  • Definition of RxSwift
  • Example of RxSwift
  • 補充

Definition of ReactiveX:

  • An API for asynchronous programming with observable streams.
  • ReactiveX is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming.
  • ReactiveX是一組tool讓指令式程式設計(imperative programming)的程式語言能夠不用管資料是同步或非同步的狀況下去操作資料序列。它提供了一組sequence operators來操作在序列上的每個item。

用一句話說明Rx:

利用observer pattern和sequence operators,讓我們能夠用宣告式(declarative)的方式去處理同步或非同步的data or event stream。

Advantage of Rx:

  • Composable, Reusable (p.s. 訂閱者模式優點)
  • Understandable and concise (p.s. Declartive優點)
  • 避免Mutable state,讓資料流呈單向流動 (p.s. Function Reactive programming優點)
  • 方便處理非同步事件(p.s. Reactive programming的優點)

Definition of RxSwift

RxSwift is the Swift-specific implementation of the Reactive Extensions standard.

Note:

有人說Rx是Functional Reactive Programing(FRP),在官方介紹中有特別說明,這不是那麼正確,Rx可能會是Functional,可能會是Reactive,但FRP是另外一件東西,在定義的上 FRP 則是隨著時間continuously(連續的)操作數值,Rx則是 discrete(離散的)

Example of RxSwift

每0.5秒輸出一個累進數值,藉由subscribe,觸發到onNext這個closure,印出收到的數值

       let observable = Observable<Int>.interval(.milliseconds(500), scheduler: MainScheduler.instance)
        observable
            .subscribe(onNext: { element in
                print(element)
            }, onError: { error in
                print(error)
            }, onCompleted: {
                print("onCompleted")
            }, onDisposed: {
                print("onDisposed")
            })

補充:

  • Observer pattern(觀察者模式)
  • Iterator pattern(疊代器模式)
  • Imperative programming(指令式程式設計)
  • Declarative programming(宣告式程式設計)
  • Functional programming(函式語言程式設計)

Collections:

  • In Rx, you begin with a collection and end with a collection
  • Rx methods, also called operators, always return a new collection and never mutate the passed collection

Ref: https://www.slideshare.net/rockncoder/a-quick-intro-to-reactivex

待整理部分:

  • Observer pattern研究與分析
  • Iterator pattern研究與分析

Ref:

https://ithelp.ithome.com.tw/articles/10237162

https://www.slideshare.net/rockncoder/a-quick-intro-to-reactivex

https://github.com/ReactiveX/RxSwift