前言
目前 iOS 领域最流行的架构,当属 MVVM+RxSwift 了,这种架构有很多优势,也有一些缺点,得根据自身的需求合理的选择。
一、MVVM
在 iOS 开发中实践 MVVM 的话,通常会把大量原来放在 Controller 里的视图逻辑和数据逻辑移到 ViewModel 里,从而有效的减轻了 Controller 的负担。
另外通过分离出来的 ViewModel 获得了更好的测试性,我们可以针对 ViewModel 来测试,解决了界面元素难于测试的问题。MVVM 通常还会和一个强大的绑定机制一同工作,一旦 ViewModel 所对应的 Model 发生变化时,ViewModel 的属性也会发生变化,而相对应的 View 也随即产生变化。
MVVM 的优点:MVVM 将逻辑交给了 ViewModel 层,控制器只需要负责数据绑定,如此一来控制器的压力就减轻了很多,而且 ViewModel 与控制器及其页面相互独立,可以很方便给 ViewModel 写单元测试,适合业务逻辑比较复杂的大型项目。
MVVM 的缺点:MVVM 学习成本比较高,需要对 ViewModel 和 View 进行双向绑定,当出现 Bug 时,会迅速被传递,比较难以调试。
MVVM 的组成:MVVM 由 Model、View、ViewModel、Controller 四部分组成:
- View 是视图显示层,只展示UI,不做任何逻辑处理,与绑定 ViewModel;
- Model 是数据模型,一般通过网络层进行一次封装;
- ViewModel 是视图模型,负责处理逻辑,包括网络请求、业务逻辑、UI逻辑等,可以把 ViewModel 想象成一个黑盒,传进去输入源后,经过 ViewModel 进行处理,得到输出源。
- Controller 是胶水层,负责拼接 UI,装配 ViewModel,并且将 ViewModel 与 View 进行绑定。
二、RxSwift
基础概念 & 核心思想
RxSwift 是 Rx 的 Swift 版本,简单来说就是基于异步 Event(事件)序列的响应式编程,可以简化异步编程方法,并提供更优雅的数据绑定,让我们可以时刻响应新的数据同时可顺序地处理它们。
发布-订阅模式是 RxSwift 所呈现的一种最直观思想,发布-订阅模式可以分为两个角色:发布者、订阅者。
订阅者的主要职责是:
- 订阅:监听并处理某个事件。其本质就是向发布者注册一个处理某个事件的闭包。
- 取消(订阅)。
发布者的主要职责是:
- 发布:分发某个事件。
基本原理是:
- 订阅者调用发布者提供的订阅方法进行订阅,从而在发布者内部注册订阅者。
- 发布者内部会维护一个订阅者列表。
- 当发布者发布事件时,会遍历订阅者列表,执行其中的处理方法(将事件作为参数传递给闭包,并执行)。
rx响应式与传统编程对比,Observable,AnyObserver,Binder等实战内容,体现在下方demo中
rx进阶概念
在编写代码时我们经常会需要检测某些值的变化(比如:textFiled 输入值的变化、数据请求完成或失败的变化),然后进行相应的处理。
- 过去针对不同的情况,我们需要采用不同的事件传递方法去处理,比如:delegate、notification、target-action、KVO 等等。
- 而 RectiveX 机制(由 RxSwift 实现)的出现,让程序里的事件传递响应方法做到统一。将之前那些常用的事件传递方法(比如:delegate、notification、target-action 等等),全部替换成 Rx 的“信号链”方式。
1.Observable-序列是用来描述元素异步产生的过程,万物皆可序列,类型有:Single、Completable、Maybe、Driver、Signal、ControlEvent
- Single 序列:要么只能发出一个元素,要么产生一个 error 事件,不会共享附加作用
- Driver 序列:不会产生 error 事件,一定在主线程回调,共享附加作用,所以 UI 序列一般都用 Driver,但是 Driver 会对新观察者重新发送上一个元素
- Signal 序列:和 Driver 序列类似,也不会产生 error 事件,一定在主线程回调,共享附加作用,区别就是,Signal 不会对新观察者回放上一个元素
2.一个序列如果发出了 error 或者 completed 事件,那么整个序列都会被终止,所有内部资源都会被释放。如果你需要提前释放这些资源或取消订阅的话,一般使用 DisposeBag 或者 takeUntil
3.有的序列有共享附加作用的特征,有的序列不共享附加作用
- 共享附加作用是指:如果一个序列共享附加作用,那在第二次订阅时,不会重新发起网络请求,而是共享第一次网络请求(附加作用),例如:Driver、Signal、ControlEvent
- 不共享附加作用是指:如果一个序列不共享附加作用,那在第二次订阅时,会重新发起网络请求,而不是共享第一次网络请求(附加作用),例如:Single、Completable、Maybe
4.Observer-观察者,是用来监听序列的,当序列产生元素时,需要对此事件作出响应,分为两种:AnyObserver、Binder
- AnyObserver 观察者可以描述任意一种观察者,例如:接受到网络请求序列的元素时,就可以用 AnyObserver 作为响应者
- Binder 观察者不会处理错误事件,并且确保响应都在给定的 Scheduler 上执行,默认是 MainScheduler,拥有这些特性它天生就是一个UI观察者,所以对 UI 序列的观察首选就是 Binder,例如:接收到用户名是否有效的序列的元素时,就可以用 Binder 作为响应者,如下图所示:
5.有一种特殊的序列,既可以是序列,又可以是观察者,例如:textField 的 text 属性,既可以看由用户输入而产生的序列,又可以看做显示内容的观察者,如下所示:
6.操作符可以帮助大家创建新的序列,也可以对原有的序列进行加工,使之成为一个新的序列,例如通过 map 操作符可以将输入的用户名,转换成用户名是否有效,从字符串序列转成了布尔值序列,这里列举几个常用的操作符:
- catchErrorJustReturn 操作符将一个 error 事件替换成其他元素,并且结束该序列,如下所示:
- combineLatest 操作符,当多个 Observables 中任何一个发出一个元素,如果其他 Observables 都已经存在元素的话,就会通过一个函数进行组合,然后发出一个元素
- map 操作符,通过一个转换函数,将 Observable 里面的每个元素都转换一遍,转换函数的闭包返回的是具体的类型,如下所示:
- flatMap 操作符,通过一个转换函数,将 Observable 序列里面的每个元素都转换成一个 Observable 序列,然后将这些序列合并,这个操作符可以将子序列的元素一次性全部发出来
- withLatestFrom 操作符将两个 Observable 最新元素通过一个函数组合,当第二个 Observable 有元素后,第一个 Observable 发出的元素就会跟第二个 Observable 的最新元素进行组合,如下所示:
6.Schedulers 是 Rx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行;
- 我们用 subscribeOn 来决定数据序列的构建函数在哪个 Scheduler 上运行;
- 我们用 observeOn 来决定在哪个 Scheduler 监听这个数据序列;
- 一个比较典型的例子就是,在后台发起网络请求,然后解析数据,最后在主线程刷新页面。你就可以先用 subscribeOn 切到后台去发送请求并解析数据,最后用 observeOn 切换到主线程更新页面,如下所示:
7.一旦序列里产出了一个 error 事件,整个序列将被终止,除非你进行了错误处理
- catchError 可以在错误产生时,用一组备用元素将错误替换掉,如下所示,当搜索出现错误时,用空数组来替换错误,以保证整个序列不会被终止
- 将泛型设置成 Result 可以将错误传递下去,可以方便我们处理错误,如下所示:
三、MVVM + RxSwift
1.如果输入源能一次性拿到,那么可以用第一种方式,通过初始化输入源得到输出源,然后在 Controller 中将输出源与观察者进行绑定,如下所示:
2.如果输入源不能一次性拿到 ,需要分批拿到输入源,就需要用第二种方式,第二种方式会在更新输入源之后同步更新输出源,如下所示: