响应式编程(Reactive Programming,简称RP),是一种编程范式,于1997年提出,可以简化异步编程,提供更优雅的数据绑定。一般与函数式融合在一起,所以也会叫做:函数响应式编程(Functional Reactive Programming,简称FRP)
比较著名的、成熟的响应式框架:
ReactiveCocoa
- 简称RAC,有Objective-C、Swift版本
- 官网: http://reactivecocoa.io/
- github:https://github.com/ReactiveCocoa
ReactiveX
- 简称Rx,有众多编程语言的版本,比如RxJava、RxKotlin、RxJS、RxCpp、RxPHP、RxGo、RxSwift等等
- 官网: http://reactivex.io/
- github: https://github.com/ReactiveX
一、 RxSwif
- RxSwift(ReactiveX for Swift),ReactiveX的Swift版本
- 源码:https://github.com/ReactiveX/RxSwift
- 中文文档: https://beeth0ven.github.io/RxSwift-Chinese-Documentation/
Podfile
use_frameworks!
target 'YOUR_TARGET_NAME’ do
pod 'RxSwift', ‘6.2.0’
pod 'RxCocoa', ‘6.2.0’
end
- RxSwift:Rx标准API的Swift实现,不包括任何iOS相关的内容
- RxCocoa:基于RxSwift,给iOS UI控件扩展了很多Rx特性
2、RxSwif的核心角色:
- Observable(可监听序列):产生事件,负责发送事件(Event)
- Observer(观察者):响应事件,负责订阅Observable,监听Observable发送的事件(Event)
2.1、Observable
所有的事物都是序列
之前我们提到,Observable 可以用于描述元素异步产生的序列。这样我们生活中许多事物都可以通过它来表示,例如:
-
Observable
温度**你可以将温度看作是一个序列,然后监测这个温度值,最后对这个值做出响应。例如:当室温高于 33 度时,打开空调降温。
-
Observable
你也可以把《海贼王》的动漫看作是一个序列。然后当《海贼王》更新一集时,我们就立即观看这一集。
Observable
JSON
你可以把网络请求的返回的 JSON 看作是一个序列。然后当取到 JSON 时,将它打印出来。Observable
任务回调
你可以把任务回调看作是一个序列。当任务结束后,提示用户任务已完成。
如何创建序列
现在我们已经可以把生活中的许多事物看作是一个序列了。那么我们要怎么创建这些序列呢?
实际上,框架已经帮我们创建好了许多常用的序列。例如:button的点击,textField的当前文本,switch的开关状态,slider的当前数值等等。
另外,有一些自定义的序列是需要我们自己创建的。这里介绍一下创建序列最基本的方法,例如,我们创建一个 [1,2,3] 的序列
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let observable = Observable.create { (observe:AnyObserver) in
observe.onNext("1")
observe.onNext("2")
observe.onNext("3")
observe.onCompleted()
return Disposables.create()
}
observable.subscribe { event in
switch event{
case let Event.next(data):print(data)
case Event.error(let error):print(error)
case Event.completed:print("completed")
}
}
}
}
创建序列最直接的方法就是调用 Observable.create,然后在构建函数里面描述元素的产生过程。 observer.onNext(0) 就代表产生了一个元素,他的值是 0。后面又产生了 9 个元素分别是 1, 2, ... 8, 9 。最后,用 observer.onCompleted() 表示元素已经全部产生,没有更多元素了。
public enum Event
{
case next(Element)
case error(Swift.Error)
case completed
}
- next - 序列产生了一个新的元素
- error - 创建序列时产生了一个错误,导致序列终止
- completed - 序列的所有元素都已经成功产生,整个序列已经完成
let observable = Observable.just("10")
let observable = Observable.of("1","2","3”)
let observable = Observable.from(["1","2","3"])
- 其中Observable.just("10")等价于 observe.onNext("10”) observe.onCompleted()
- Observable.of("1","2","3”)和Observable.from(["1","2","3”])则等价于 observe.onNext("1”) observe.onNext("2")
observe.onNext("3")
observe.onCompleted()
我们可以用以上学习的方式来封装功能组件,例如,闭包回调:
typealias JSON = Any
let json: Observable = Observable.create { (observer) -> Disposable in
let task = URLSession.shared.dataTask(with: ...) { data, _, error in
guard error == nil else {
observer.onError(error!)
return
}
guard let data = data,
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
else {
observer.onError(DataError.cantParseJSON)
return
}
observer.onNext(jsonObject)
observer.onCompleted()
}
task.resume()
return Disposables.create { task.cancel() }
}
json
.subscribe(onNext: { json in
print("取得 json 成功: \(json)")
}, onError: { error in
print("取得 json 失败 Error: \(error.localizedDescription)")
}, onCompleted: {
print("取得 json 任务成功完成")
})
.disposed(by: disposeBag)
2.2、Observer
在上面我们虽然只学习如何创建一个Observable,但是在上面其实我们已经接触到了Observer。回忆一下上面对Observable的监听是这样的。
observable.subscribe { event in
switch event{
case let Event.next(data):print(data)
case Event.error(let error):print(error)
case Event.completed:print("completed")
}
}
创建观察者最直接的方法就是在 Observable 的 subscribe 方法后面描述,事件发生时,需要如何做出响应。而观察者就是由后面的 onNext,onError,onCompleted的这些闭包构建出来的。
observable.subscribe(onNext: { data in
print(data)
}, onError: { error in
print("发生错误: \(error.localizedDescription)")
}, onCompleted: {
print("任务完成")
})
那么如何自己去创建一个Observer对象呢?
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let observer = AnyObserver.init { event in
switch event {
case .next(let data):print(data)
case .completed:print("completed")
case .error(let error):
print(error)
}
}
Observable.just(1).subscribe(observer)
}
}
- AnyObserver 可以用来描叙任意一种观察者。
Binder
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let observer:Binder = Binder(self) { (target,age:Int) in
print(target)
}
Observable.just(5).bind(to: observer)
}
}
- Binder也是一个observer
- Binder主要有以下两个特征:
1、不会处理错误事件
2、确保绑定都是在给定Scheduler上执行(默认 MainScheduler)
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let lable = UILabel()
self.view .addSubview(lable)
lable.backgroundColor = .red
lable.frame = CGRect(x: 100, y: 100, width: 100, height: 40)
let binder = Binder(lable) {(lable, str:String) in
lable.text = str
}
Observable.just("test").bind(to:binder)
}
}
- 这里的observer是一个UI观察者,只会处理 next 事件,并且更新 UI 的操作需要在主线程上执行,因此建议使用 Binder是更好的方案。
Disposable
每当Observable被订阅时,都会返回一个Disposable实例,当调用Disposable的dispose,就相当于取消订阅。
- dispose():立即取消订阅
- disposed(by bag: DisposeBag):当bag销毁时,会自动调用Disposable实例的dispose。
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let lable = UILabel()
let bag = DisposeBag()
self.view .addSubview(lable)
lable.backgroundColor = .red
lable.frame = CGRect(x: 100, y: 100, width: 100, height: 40)
let binder = Binder(lable) {(lable, str:String) in
lable.text = str
}
Observable.just("test").bind(to:binder).disposed(by: bag)
}
}
在这里bag作为控制器的成员变量,只有ViewController销毁时,bag才会被销毁,也只有这时才会被取消订阅。
- 使用清除包(DisposeBag),我们就可以让ARC 来管理订阅的生命周期了。
2.3、补充
框架已经帮我们创建好了许多常用的序列。例如:button的点击,textField的当前文本,switch的开关状态,slider的当前数值等等。
let btn = UIButton()
let textFiled = UITextField()
let slider = UISlider()
let switchs = UISwitch()
btn.rx.tap.subscribe { event in}.dispose()
textFiled.rx.text.subscribe { event in}.dispose()
slider.rx.value.subscribe { event in}.dispose()
switchs.rx.isOn.subscribe { event in}.dispose()
在我们所遇到的事物中,有一部分非常特别。它们既是可监听序列也是观察者。
例如:textField的当前文本。它可以看成是由用户输入,而产生的一个文本序列。也可以是由外部文本序列,来控制当前显示内容的观察者:
// 作为可监听序列
let observable = textField.rx.text
observable.subscribe(onNext: { text in show(text: text) })
// 作为观察者
let observer = textField.rx.text
let text: Observable = ...
text.bind(to: observer)
有许多 UI 控件都存在这种特性,例如:switch的开关状态,segmentedControl的选中索引号,datePicker的选中日期等等。
扩展Binder属性
extension Reactive where Base: UIControl {
var hidden: Binder {
Binder(base) { button, value in
button.isHidden = value
}
}
Observable.just(1).map { "数值:\($0)" }.bind(to: button.rx.hidden).dispose()