📂
RxSwift
  • RxSwift 中文文档
  • 1. 为什么要使用 RxSwift?
  • 2. 你好 RxSwift!
  • 3. 函数响应式编程
    • 3.1 函数式编程
    • 3.2 函数式编程 -> 函数响应式编程
    • 3.3 数据绑定
  • 4. RxSwift 核心
    • 4.1 Observable - 可监听序列
      • Single
      • Completable
      • Maybe
      • Driver
      • Signal
      • ControlEvent
    • 4.2 Observer - 观察者
      • AnyObserver
      • Binder
    • 4.3 Observable & Observer 既是可监听序列也是观察者
      • AsyncSubject
      • PublishSubject
      • ReplaySubject
      • BehaviorSubject
      • Variable(已弃用)
      • ControlProperty
    • 4.4 Operator - 操作符
    • 4.5 Disposable - 可被清除的资源
    • 4.6 Schedulers - 调度器
    • 4.7 Error Handling - 错误处理
  • 5. 如何选择操作符?
    • amb
    • buffer
    • catchError
    • combineLatest
    • concat
    • concatMap
    • connect
    • create
    • debounce
    • debug
    • deferred
    • delay
    • delaySubscription
    • dematerialize
    • distinctUntilChanged
    • do
    • elementAt
    • empty
    • error
    • filter
    • flatMap
    • flatMapLatest
    • from
    • groupBy
    • ignoreElements
    • interval
    • just
    • map
    • merge
    • materialize
    • never
    • observeOn
    • publish
    • reduce
    • refCount
    • repeatElement
    • replay
    • retry
    • sample
    • scan
    • shareReplay
    • single
    • skip
    • skipUntil
    • skipWhile
    • startWith
    • subscribeOn
    • take
    • takeLast
    • takeUntil
    • takeWhile
    • timeout
    • timer
    • using
    • window
    • withLatestFrom
    • zip
  • 6. 更多示例
    • ImagePicker - 图片选择器
    • TableViewSectionedViewController - 多层级的列表页
    • Calculator - 计算器
  • 7. RxSwift 常用架构
    • 7.1 MVVM
      • Github Signup(示例)
    • 7.2 RxFeedback
      • Github Search(示例)
    • 7.3 ReactorKit
      • Github Search(示例)
  • 8. RxSwift 生态系统
  • 9. 学习资源
  • 10. 关于本文档
    • 10.1 文档更新日志
  • 食谱
    • RxSwift 5 更新了什么?
    • RxRelay
    • 纯函数
    • 附加作用
    • 共享附加作用
Powered by GitBook
On this page
  • MVC
  • MVVM
  • 示例
  • ViewModel
  • ViewController
  • 示例

Was this helpful?

  1. 7. RxSwift 常用架构

7.1 MVVM

Previous7. RxSwift 常用架构NextGithub Signup(示例)

Last updated 4 years ago

Was this helpful?

MVVM 是 Model-View-ViewModel 的简写。如果你已经对 非常熟悉了,那么上手 MVVM 也是非常容易的。

MVC

MVC 是 Model-View-Controller 的简写。MVC 主要有三层:

  • Model 数据层,读写数据,保存 App 状态

  • View 页面层,和用户交互,向用户显示页面,反馈用户行为

  • ViewController 逻辑层,更新数据,或者页面,处理业务逻辑

MVC 可以帮助你很好的将数据,页面,逻辑的代码分离开来。使得每一层相对独立。这样你就能够将一些可复用的功能抽离出来,化繁为简。只不过,一旦 App 的交互变复杂,你就会发现 ViewController 将变得十分臃肿。大量代码被添加到控制器中,使得控制器负担过重。此时,你就需要想办法将控制器里面的代码进一步地分离出来,对 APP 进行重新分层。而 MVVM 就是一种进阶的分层方案。

MVVM

MVVM 和 MVC 十分相识。只不过他的分层更加详细:

  • Model 数据层,读写数据,保存 App 状态

  • View 页面层,提供用户输入行为,并且显示输出状态

  • ViewModel 逻辑层,它将用户输入行为,转换成输出状态

  • ViewController 主要负责数据绑定

没错,ViewModel 现在是逻辑层,而控制器只需要负责数据绑定。如此一来控制器的负担就减轻了许多。并且 ViewModel 与控制器以及页面相独立。那么,你就可以跨平台使用它。你也可以很容易地测试它。

示例

重构前:

class SimpleValidationViewController : ViewController {

    ...

    override func viewDidLoad() {
        super.viewDidLoad()

        ...

        let usernameValid = usernameOutlet.rx.text.orEmpty
            .map { $0.characters.count >= minimalUsernameLength }
            .share(replay: 1)

        let passwordValid = passwordOutlet.rx.text.orEmpty
            .map { $0.characters.count >= minimalPasswordLength }
            .share(replay: 1)

        let everythingValid = Observable.combineLatest(
              usernameValid,
              passwordValid
            ) { $0 && $1 }
            .share(replay: 1)

        usernameValid
            .bind(to: passwordOutlet.rx.isEnabled)
            .disposed(by: disposeBag)

        usernameValid
            .bind(to: usernameValidOutlet.rx.isHidden)
            .disposed(by: disposeBag)

        passwordValid
            .bind(to: passwordValidOutlet.rx.isHidden)
            .disposed(by: disposeBag)

        everythingValid
            .bind(to: doSomethingOutlet.rx.isEnabled)
            .disposed(by: disposeBag)

        doSomethingOutlet.rx.tap
            .subscribe(onNext: { [weak self] in self?.showAlert() })
            .disposed(by: disposeBag)
    }

    ...

}

ViewModel

ViewModel 将用户输入行为,转换成输出的状态:

class SimpleValidationViewModel {

    // 输出
    let usernameValid: Observable<Bool>
    let passwordValid: Observable<Bool>
    let everythingValid: Observable<Bool>

    // 输入 -> 输出
    init(
        username: Observable<String>,
        password: Observable<String>
        ) {

        usernameValid = username
            .map { $0.characters.count >= minimalUsernameLength }
            .share(replay: 1)

        passwordValid = password
            .map { $0.characters.count >= minimalPasswordLength }
            .share(replay: 1)

        everythingValid = Observable.combineLatest(usernameValid, passwordValid) { $0 && $1 }
            .share(replay: 1)

    }
}

输入:

  • username 输入的用户名

  • password 输入的密码

输出:

  • usernameValid 用户名是否有效

  • passwordValid 密码是否有效

  • everythingValid 所有输入是否有效

在 init 方法内部,将输入转换为输出。

ViewController

ViewController 主要负责数据绑定:

class SimpleValidationViewController : ViewController {

    ...

    private var viewModel: SimpleValidationViewModel!

    override func viewDidLoad() {
        super.viewDidLoad()

        ...

        viewModel = SimpleValidationViewModel(
            username: usernameOutlet.rx.text.orEmpty.asObservable(),
            password: passwordOutlet.rx.text.orEmpty.asObservable()
        )

        viewModel.usernameValid
            .bind(to: passwordOutlet.rx.isEnabled)
            .disposed(by: disposeBag)

        viewModel.usernameValid
            .bind(to: usernameValidOutlet.rx.isHidden)
            .disposed(by: disposeBag)

        viewModel.passwordValid
            .bind(to: passwordValidOutlet.rx.isHidden)
            .disposed(by: disposeBag)

        viewModel.everythingValid
            .bind(to: doSomethingOutlet.rx.isEnabled)
            .disposed(by: disposeBag)

        doSomethingOutlet.rx.tap
            .subscribe(onNext: { [weak self] in self?.showAlert() })
            .disposed(by: disposeBag)
    }

    ...

}

输入:

  • username 将输入的用户名传入 ViewModel

  • password 将输入的密码传入 ViewModel

输出:

  • usernameValid 用用户名是否有效,来控制提示语是否隐藏,密码输入框是否可用

  • passwordValid 用密码是否有效,来控制提示语是否隐藏

  • everythingValid 用两者是否同时有效,来控制按钮是否可点击

当 App 的交互变复杂时,你仍然可以保持控制器结构清晰。这样可以大大的提升代码可读性。将来代码维护起来也就会容易许多了。

示例

这里我们将用 MVVM 来重构。

下一节将用 来演示如何使用 MVVM。

注意⚠️:这里介绍的 MVVM 并不是严格意义上的 MVVM。但我们通常都管它叫 MVVM,而且它配合 RxSwift 使用起来非常方便。如需了解什么是严格意义上的 MVVM,请参考微软的 。

输入验证
Github Signup
The MVVM Pattern
MVC