简介
ReactiveX(简写: Rx) 是一个可以帮助我们简化异步编程的框架。
它拓展了观察者模式。使你能够自由组合多个异步事件,而不需要去关心线程,同步,线程安全,并发数据以及I/O阻塞。
RxSwift 是 Rx 的 Swift 版本。它尝试将原有的一些概念移植到 iOS/macOS 平台。你可以在这里找到跨平台文档 ReactiveX.io。
RxSwift全称ReactiveX for Swift,是一个简化异步编程的框架,实现了函数响应式编程,事件与对象紧密联系,业务流清晰,便于管理。在RxSwift中,所有异步操作(事件)和数据流均被抽象为可观察序列的概念。
反应式编程到底是什么呢?
在计算领域,响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。——百度百科
阅读这一段之后,大多数人会不知道反应性编程实际上是什么。 这就是为什么我将尝试写这篇文档。通过使用Swift版本的Rx来介绍这个现代的软件开发方法
1. Observable Sequences
首先需要理解的是,RxSwift中的所有东西都是可观察序列(Observable Sequences),或者是操作或订阅由可观察序列发出的事件的东西。
数组、字符串或字典将在RxSwift中转换为可观察序列。这些已经被集成在RxSwift中。 当然,你还可以创建自定义的可观察序列。只需要符合序列协议(Sequence Protocol)
创建一些可观察序列:
let helloSequence = Observable.just("Hello Rx")
let fibonacciSequence = Observable.from([0,1,1,2,3,5,8])
let dictSequence = Observable.from([1:"Hello",2:"World"])
订阅可观察序列
subscribe(on:(Event<T>)-> ()).
闭包将接收该序列发出的所有事件
let helloSequence = Observable.of("Hello Rx")
let subscription = helloSequence.subscribe { event in
print(event)
}
打印结果
next(Hello Rx)
completed
2. Event
可观察序列在其生命周期中可以发出零个或多个事件。 在RxSwift中,事件只是一个枚举类型,有3种可能的状态:
-
.next(value: T)
当一个值或一组值被添加到一个可观察序列中时,它会像上面看到的那样将下一个事件发送给它的订阅者。关联的值将包含序列中的实际值。
-
.error(error: error)
如果遇到错误,序列会发出一个错误事件。这也将终止序列。
-
.completed
如果一个序列正常结束,它会向订阅者发送一个完成的事件
let bag = DisposeBag() let helloSequence = Observable.from(["H","e","l","l"," let subscription = helloSequence.subscribe { event in switch event { case .next(let value): print(value) case .error(let error): print(error) case .completed: print("completed") } } .disposed(by: bag) 打印: H e l l o completed
如果您想取消订阅,可以通过对订阅调用dispose来实现。您也可以添加订阅到一个处置袋,它将取消订阅自动对处置袋实例的deinit。
3. Observable & Observer
有一类事物既是可观察序列的一种特殊形式,可以订阅它并动态地向它添加元素。目前RxSwift中有4种不同的类别
- PublishSubject:如果你订阅了它,你将得到订阅后的所有事件
- BehaviourSubject:行为主体将向订阅者提供最新的元素以及订阅发生后该序列所发出的所有内容
- ReplaySubject:将对观察者发送全部的元素,无论观察者是何时进行订阅的
- AsyncSubject 将在源 Observable 产生完成事件后,发出最后一个元素(仅仅只有最后一个元素),如果源 Observable 没有发出任何元素,只有一个完成事件。那 AsyncSubject 也只有一个完成事件。
以上四者的主要区别:在订阅的时候,收到的过去发送的时间的个数
| Subject | 收到过去事件的个数 |
|---|---|
| PublishSubject | 0 |
| BehaviourSubject | 1 |
| ReplaySubject | N |
| AsyncSubject | 0 |
用法举例:
let bag = DisposeBag()
let publishSubject = PublishSubject<String>()
let subscription1 = publishSubject.subscribe(onNext:{
print($0)
}).addDisposableTo(bag)
publishSubject.onNext("Hello")
publishSubject.onNext("Again")
// Subscription1 收到Hello和Again, Subscription2 不会收到事件
let subscription2 = publishSubject.subscribe(onNext:{
print(#line,$0)
})
publishSubject.onNext("Subscription1和Subscription2都会收到")
4. Schedulers
操作符将在创建订阅的线程上工作。在RxSwift中,使用调度程序强制操作符在特定队列上执行它们的工作。还可以强制将订阅发生在一个特定的队列上。可以对这些任务使用subscribeOn和observeOn。类似于GCD或操作队列。在RxSwift有5种类型的调度
-
MainScheduler
需要在主线程上执行的工作。如果从主线程调用调度方法,它将立即执行操作而不进行调度。这个调度器通常用于执行UI工作。
-
CurrentThreadScheduler
在当前线程上派发工作。这是生成元素的默认调度线程。
-
SerialDispatchQueueScheduler
需要在特定dispatch_queue_t上执行的工作。主调度程序是SerialDispatchQueueScheduler的一个实例。
-
ConcurrentDispatchQueueScheduler
需要在特定的dispatch_queue_t上执行的工作。这个调度器很适合为某些需要在后台执行的工作
-
OperationQueueScheduler
需要在特定NSOperationQueue上执行的工作。该调度器适用于以下情况:需要在后台执行较大的工作块,并且希望使用maxConcurrentOperationCount对并发处理进行微调。
举例演示如何观察一个在后台的任务,并且在主线程订阅
let publish1 = PublishSubject<Int>()
let publish2 = PublishSubject<Int>()
let concurrentScheduler = ConcurrentDispatchQueueScheduler(qos: .background)
Observable.of(publish1,publish2)
.observeOn(concurrentScheduler)
.merge()
.subscribeOn(MainScheduler())
.subscribe(onNext:{
print($0)
})
publish1.onNext(20)
publish1.onNext(40)
5. 项目改造实践 - 使用RxGesture
使用RxGesture之后,不用再单独创建手势,不用添加手势。 封装的tapGesture属性内部做了这些事情
原来的实现
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectedView(sender:))))
@objc func handleSelectedView(sender: UITapGestureRecognizer) {
something()
}
改造后
self.rx
.tapGesture()
.when(.recognized)
.subscribe(onNext:{ gesture in
something()
})
.disposed(by: bag)