# 淺談 RxSwift + MVVM 使用 > [time=Mon, Apr 25, 2022 9:30 AM] ###### tags: `RxSwfit` `MVVM` 假設現在有一簡單註冊需求: 1. 帳號輸入框;`帳號`最少 `6` 個字。 2. 密碼輸入框;`密碼`最少 `8` 個字。 3. 驗證密碼輸入框;`驗證密碼`需與`密碼`完全相同。 4. 註冊送出按鈕;按下送出後檢查上述條件。 5. 註冊成功;彈出提示 `註冊成功`,反之`註冊失敗`。 現在在腦裡假想一下,該怎麼實作以上需求。 > 沒有意外通常都是實作 UITextFieldDelegate 判斷當前的 textField 後再處理需求。 ## 一、實作範例 > 完整程式碼參閱 [GitHub](https://github.com/hoclos/RxSwiftDemo/releases/tag/v1) tag: v1。 > tag: v2 為 viewModel 優化,將 input、output 拆分,使用上會更清楚。 ### 1. 建立 viewModel ``` protocol RegisterViewModelPrototype { // } class RegisterViewModel: RegisterViewModelPrototype { // } ``` ### 2. 定義 protocol ``` protocol RegisterViewModelPrototype { /// 註冊結果 var registerResult: PublishRelay<RegisterViewModel.RegisterResult> { get } /// 帳號 var accountString: BehaviorRelay<String?> { get } /// 密碼 var passwordString: BehaviorRelay<String?> { get } /// 驗證密碼 var verifyPasswordString: BehaviorRelay<String?> { get } /// 送出註冊 func register() } ``` ### 3. ViewController binding ``` func bind(_ viewModel: RegisterViewModelPrototype) { viewModel .registerResult .subscribe(onNext: { [weak self] result in ... }) .disposed(by: disposeBag) ... } ``` ### 4. ViewModel 判斷實作 ``` func register() { guard let accountString = accountString.value, accountString.count >= 6, let passwordString = passwordString.value, passwordString.count >= 8, let verifyPasswordString = verifyPasswordString.value, passwordString == verifyPasswordString else { registerResult.accept(.failed) return } registerResult.accept(.successful) } ``` ## 二、MVVM 在開始談論 `RxSwift` 之前我們先理解一下 [MVVM](https://zh.wikipedia.org/wiki/MVVM) (Model–view–viewmodel),詳細原理請直接參照維基百科。 ![](https://i.imgur.com/P2ykRpx.png) 用 MVVM 的好處是什麼? * 讓程式碼之間不再耦合,畫面控件、邏輯不會糾纏不清。 * ~~再也不怕畫面改來改去。~~ ## 三、RxSwift [RxSwift](https://github.com/ReactiveX/RxSwift) 就是 [ReactiveX](https://reactivex.io/) 的 Swift 版本,是一個函式響應式框架,遵循 Functional Reactive Programming(FRP) 的設計規範,它把事件封裝成訊號流,並採用觀察者模式來實現。 ### 1. Observable / Observer 這兩個名詞是所有 RxSwift 初學者必定會接觸的東西同時這也是貫穿整個 RxSwift 的重點。 * Observable (可觀察的對象) -- 嬰兒 * Observer (觀察者) -- 父母 當 `Observable` 送出訊號時,`Observer` 收到並做相對應處理。 舉例:當嬰兒哭泣,爸媽立刻動身探視。 ### 2. 常見用法 * Observable #### - BehaviorRelay > BehaviorSubject 去掉終止事件 `onError` 或 `onCompleted`。 初始的時候可以帶預設值,會持有 `value`;訂閱的時候就會送出訊號。 #### - PublishRelay > PublishSubject 去掉終止事件 `onError` 或 `onCompleted`。 初始的時候沒有帶預設值,不會持有 `value`;訂閱的時候不會送出訊號,被觸發才會。 #### - subscribe * Observer ``` public enum Event<Element> { case next(Element) case error(Swift.Error) case completed } ``` 接收 `Observable` 的 `Event` 訊號,進行後續處理。 #### - DisposeBag 跟隨生命週期控制 `訂閱事件` 的釋放。 ### 3. 常見錯誤 ``` var string1 = BehaviorRelay<String?>(value: nil) var string2 = PublishRelay<String>() ``` 因 `BehaviorRelay`、`PublishRelay` 本身為容器非變數,所以正確應寫 `let` 而非 `var`。 ### 4. 更多關於 RxSwift 的語法 請詳閱 [RxSwift 中文文檔](https://beeth0ven.github.io/RxSwift-Chinese-Documentation/)。 ## 四、總結 > 以上做法是非常淺入的寫法。 只需要實作幾個環節就能完成本文一開始的簡單需求,以上全部僅為個人的簡單見解如有錯誤請不吝指教。 希望可以一起進步。 ___ * 參考 https://github.com/ReactiveX/RxSwift * 參考 https://reactivex.io/ * 參考 https://codertw.com/ios/96818/ * 參考 https://medium.com/@DianQK/rxswift-%E4%BB%8B%E7%BB%8D-ce078367c42a/ * 參考 https://beeth0ven.github.io/RxSwift-Chinese-Documentation/