一、RxSwift (Rx)
Rx
是一个关于函数响应式编程的框架,用来解决代理 、通知 、回调传递数据 、多个对象之间状态改变引起的数据流动等不符合模块之间高内聚低耦合思想的问题,可以将数据流动按照链式调用的顺序进行传递,达到业务逻辑分离的目的。
Redux的介绍
先了解一下redux
来帮助理清Rx
的架构思路,redux
是帮助统一管理state
,通过action
来触发state
改变的框架,它的基本架构图如下:

reducer
函数是接受oldState
并进行一定处理返回newState
的纯函数,它在store
一开始构建的时候就进行赋值,其作用是用来监听state
的改变。subscribe
是订阅的意思,在该回调函数中程序员可以拿到newState
并进行自己定义的业务逻辑处理,订阅者就是store
,也可以理解为被观察者 。dispatch
在触发state
发生改变或者说是某个action
发生时进行调用,reducer
内部通过判断是哪个action
来返回相应的newState
,并通过subscribe
进行回调传递,这样程序员就可以拿到新的值进行处理。
Rx的理解
返回来说Rx
,这是一个基本的使用方式
scrollView.rx.contentOffset
.subscribe(onNext: { contentOffset in
print("contentOffset: \(contentOffset)")
})
.disposed(by: disposeBag)
在Rx中数据的流动方式为:
数据产生源——>某个action被触发或者某个state发生改变——>进行业务逻辑处理——>数据接收者
数据按照这个过程进行流动,经过业务处理后被赋值给数据接受者,从而达到我们想要的结果。对于上面的代码:
scrollView
是数据产生源,contentOffset
在这段代码中是真正的被观察者和数据产生源onNext
回调中是业务逻辑处理的代码,数据接收者这里没有出现,我可以把拿到的数据赋值给某个属性某个参数等等。
和redux
进行比较发现有这相似之处:
-
scrollView
就是store
,contentOffset
就是某个具体的state
,发生滚动是action
,发生滚动时Rx
内部进行了监听并触发了类似dispatch
的函数使得subcribe
中我们自己的业务代码被执行。 -
这就很好理解
Rx
中的Observable(可观察序列)
,也就是被观察者 、数据产生源 ,由它去注册监听(也就是执行subcribe
),而Observer(观察者)
和reducer
(这是一个抽象的称呼,代表将oldState
经过一系列转换得到newState
的纯函数)是Rx
内部帮我们做好了并隐藏起来,这对使用来说非常方便,但对理解内部逻辑和自定义Observable
和Observer
是比较困难的。
下面是自定义Observable
的一段代码:
let json: Observable<JSON> = Observable.create { (observer) -> Disposable in
let task = URLSession.shared.dataTask(with: ...) { data, _, error in
guard error == nil else {
observer.onError(error!) // 发生错误需要进行error的回调
return
}
guard let data = data,
···json序列化转换处理
else {
observer.onError(DataError.cantParseJSON) // 转换失败进行error回调
return
}
observer.onNext(jsonObject) // 得到结果,也就是oldState——》newState成功,将结 果回调出去,进行业务处理
observer.onCompleted() // 完成的回调
}
task.resume()
return Disposables.create { task.cancel() } // 资源回收是取消task
}
//
// 对于上面的回调函数具体实现,拿到数据进行业务处理
json
.subscribe(onNext: { json in
print("取得 json 成功: \(json)")
}, onError: { error in
print("取得 json 失败 Error: \(error.localizedDescription)")
}, onCompleted: {
print("取得 json 任务成功完成")
})
.disposed(by: disposeBag)
根据上面的代码可以对我们的理解进行进一步验证:
- 可以看到
create
方法的参数是一个闭包,内部有个已经定义好的observer
,拿到初始数据oldState
(在上段代码中是请求回来的data
,也可以是scoreView
开始滚动时的contentOffset
) - 经过某个
action
后(这里action
比较抽象,可以理解为点击、滚动、序列化 等等)进行数据转换处理得到newState
(在上段代码中是json
序列化后的jsonObject
,也可以是scoreView
停止滚动后的contentOffset
),这就相当于redux
中的reducer
部分,也就是隐藏起来的观察者监听值改变的部分。onNext
捕获newState
并执行相应的回调(一般来说就是程序员自定义的业务逻辑代码),通过onError
、onCompleted
监听出错或者完成状态并执行回调。 - 不像传统的
KVO
需要进行addObserver
来指定一个观察者,这里每个Observable
都有一一对应的Observer
,且创建时就隐藏在内部。理解了这些部分就可以正常使用Rx
了。
如果是监听UI的改变,有一些更简便的用法,通过Binder
,只会处理next
事件,并且更新UI 的操作需要在主线程上执行。例如view
隐藏的isHidden
属性通常是数据的接收者 ,因此Rx
帮我们做好了封装:
// 对UIview中某个熟悉的扩展,可以用来被绑定
extension Reactive where Base: UIView {
public var isHidden: Binder<Bool> {
return Binder(self.base) { view, hidden in
view.isHidden = hidden
}
}
}
// passwordOutlet是文本输入框
passwordOutlet.rx.text.orEmpty
.map { $0.characters.count >= minimalPasswordLength }
.bind(to: passwordValidOutlet.rx.isHidden) // isHidden是数据的接收者
.disposed(by: disposeBag)
除了上面介绍的之外还有多种Subject
,是Observable
和Observer
的结合体,也就是既可以注册监听(调用subscribe
),也可以当观察者调用onNext
发送数据。另外有许多操作符可以对数据进行多种转换,具体参考官网手册。
二、MVVM:
- 先了解MVC,下面是它的架构图:
可以看出View
跟Model
事实上是没有交互的,由Controller
负责Model
与View
之间的交互,交互越多,Controller
就越臃肿。目前对MVC架构划分是Model
作为数据管理者,View
作为数据展示者,Controller
进行业务处理和数据传递。
摘自Casa Taloyum的划分
M应该做的事:
1.给ViewController提供数据
2.给ViewController存储数据提供接口
3.提供经过抽象的业务基本组件,供Controller调度
C应该做的事:
1.管理View Container的生命周期
2.负责生成所有的View实例,并放入View Container
3.监听来自View与业务有关的事件,通过与Model的合作,来完成对应事件的业务。
V应该做的事:
1.响应与业务无关的事件,并因此引发动画效果,点击反馈(如果合适的话,尽量还是放在View去做)等。 2.界面元素表达
- MVVM架构图:
抽出了ViewModel
层来负责数据与视图的交互部分,Controller
仅协调各个部分的绑定关系以及必要的逻辑处理。结合Rx
进行双向绑定: 1、view
当做Observable
,通过subscribe
中的回调onNext
将数据传递给viewmodel
中的具体业务处理函数 2、viewModel
当做Observable
,通过subscribe
中的回调onNext
将处理后的数据传递给model
,当然也可以通过将model
持有为属性来更新数据 所以viewmodel
最好是一个Subject
类型,方便后续的使用。