1. RxSwift简介
- RxSwift 的效果
1)在编写代码时咱们经常会需求检测某些值的改变(比方:textFiled 输入值的改变、数据恳求完结或失利的改变),然后进行相应的处理。
曩昔针对不同的状况,咱们需求采用不同的事情传递办法去处理,比方:delegate、notification、target-action、KVO 等等。
而 RectiveX 机制(由 RxSwift 完结)的呈现,让程序里的事情传递呼应办法做到统一。将之前那些常用的事情传递办法(比方:delegate、notification、target-action 等等),悉数替换成 Rx 的“信号链”办法。
(2)假如咱们平时运用的是 MVVM 开发办法的话,经过 RxSwift 能够获得愈加便利的数据绑定的办法,使得 MVVM 开发愈加如虎添翼。
- RxSwift 与 RxCocoa
RxSwift:它只是基于 Swift 言语的 Rx 标准完结接口库,所以 RxSwift 里不包含任何 Cocoa 或许 UI 方面的类。
RxCocoa:是基于 RxSwift 针关于 iOS 开发的一个库,它经过 Extension 的办法给原生的比方 UI 控件添加了 Rx 的特性,使得咱们更容易订阅和呼应这些控件的事情。
Swift书本材料下载:下载地址
2. RxSwift简略运用
2.1 呼应式编程与传统式编程的比较样例
- 实例2.1
- 有这么一个需求:
表格中显现的是歌曲信息(歌名,以及歌手)
点击选中恣意一个单元格,在操控台中打印出对应的歌曲信息。
- 按传统办法:首要咱们创立一个 Music 的结构体,用来保存歌曲名称、歌手姓名。此外它还遵循 CustomStringConvertible 协议,便利咱们输出调试。
import UIKit
//歌曲结构体
struct Music {
let name: String //歌名
let singer: String //演唱者
init(name: String, singer: String) {
self.name = name
self.singer = singer
}
}
//完结 CustomStringConvertible 协议,便利输出调试
extension Music: CustomStringConvertible {
var description: String {
return "name:\(name) singer:\(singer)"
}
}
2.1.1 传统编程
- 首要写一个 ViewModel
import Foundation
//歌曲列表数据源
struct MusicListViewModel {
let data = [
Music(name: "无条件", singer: "陈奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "从前的我", singer: "陈洁仪"),
Music(name: "在木星", singer: "朴树"),
]
}
- 视图操控器代码(ViewController.swift)
- 接着咱们设置 UITableView 的托付,并让视图操控器完结 UITableViewDataSource 和 UITableViewDelegate 协议,及相关的协议办法。
- 这个咱们肯定都写过无数遍了,也没什么好讲的。算一下,这儿一共需求 43 行代码。
import UIKit
import RxSwift
class ViewController: UIViewController {
//tableView目标
@IBOutlet weak var tableView: UITableView!
//歌曲列表数据源
let musicListViewModel = MusicListViewModel()
override func viewDidLoad() {
super.viewDidLoad()
//设置署理
tableView.dataSource = self
tableView.delegate = self
}
}
extension ViewController: UITableViewDataSource {
//回来单元格数量
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return musicListViewModel.data.count
}
//回来对应的单元格
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell")!
let music = musicListViewModel.data[indexPath.row]
cell.textLabel?.text = music.name
cell.detailTextLabel?.text = music.singer
return cell
}
}
extension ViewController: UITableViewDelegate {
//单元格点击
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("你选中的歌曲信息【\(musicListViewModel.data[indexPath.row])】")
}
}
- 下面来看一下Rxswift的编程
2.1.2 Rxswift编程
- 对
ViewModel
做些修正- 这儿咱们将 data 特点变成一个可调查序列目标(
Observable Squence
),而目标傍边的内容和咱们之前在数组傍边所包含的内容是彻底相同的。 - 关于可调查序列目标在后边的文章中我会详细介绍。简略说便是“序列”能够对这些数值进行“订阅(
Subscribe
)”,有点相似于“告诉(NotificationCenter
)”
- 这儿咱们将 data 特点变成一个可调查序列目标(
import RxSwift
//歌曲列表数据源
struct MusicListViewModel {
let data = Observable.just([
Music(name: "无条件", singer: "陈奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "从前的我", singer: "陈洁仪"),
Music(name: "在木星", singer: "朴树"),
])
}
- 视图操控器代码(ViewController.swift)
- 这儿咱们不再需求完结数据源和托付协议了。而是写一些呼应式代码,让它们将数据和 UITableView 建立绑定联系。
- 算了下这儿咱们只需求 31 行代码,同之前的比较,一下减少了 1/4 代码量。并且代码也更清爽了些。
-
代码的简略说明:
DisposeBag
:效果是 Rx 在视图操控器或许其持有者即将毁掉的时分,主动释法掉绑定在它上面的资源。它是经过相似“订阅处置机制”办法完结(相似于 NotificationCenter 的 removeObserver)。rx.items(cellIdentifier:
):这是 Rx 基于 cellForRowAt 数据源办法的一个封装。传统办法中咱们还要有个 numberOfRowsInSection 办法,运用 Rx 后就不再需求了(Rx 现已帮咱们完结了相关工作)。rx.modelSelected
: 这是 Rx 基于 UITableView 托付回调办法 didSelectRowAt 的一个封装。
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//tableView目标
@IBOutlet weak var tableView: UITableView!
//歌曲列表数据源
let musicListViewModel = MusicListViewModel()
//担任目标毁掉
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//将数据源数据绑定到tableView上
musicListViewModel.data
.bind(to: tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell in
cell.textLabel?.text = music.name
cell.detailTextLabel?.text = music.singer
}.disposed(by: disposeBag)
//tableView点击呼应
tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
print("你选中的歌曲信息【\(music)】")
}).disposed(by: disposeBag)
}
}
2.2 Observable介绍、创立可调查序列
- Observable 作为 Rx 的根基,咱们首要对它要有一些根本的了解。
- Observable:
Observable 这个类便是 Rx 结构的基础,咱们能够称它为可调查序列。它的效果便是能够异步地发生一系列的 Event(事情),即一个 Observable 目标会跟着时刻推移不定期地宣布 event(element : T) 这样一个东西。
并且这些 Event 还能够带着数据,它的泛型 便是用来指定这个 Event 带着的数据的类型。
有了可调查序列,咱们还需求有一个 Observer(订阅者)来订阅它,这样这个订阅者才干收到 Observable 不时宣布的 Event。
- Event
- 查看 RxSwift 源码能够发现,事情 Event 的定义如下:
public enum Event<Element> {
/// Next element is produced.
case next(Element)
/// Sequence terminated with an error.
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
- 能够看到 Event 便是一个枚举,也便是说一个 Observable 是能够宣布 3 种不同类型的 Event 事情:
-
next:
next
事情便是那个能够带着数据 的事情,能够说它便是一个“最正常”的事情。 -
error:
error
事情表明一个过错,它能够带着具体的过错内容,一旦Observable
宣布了error event
,则这个Observable
就等于中止了,以后它再也不会宣布 event 事情了。 -
completed:
completed
事情表明Observable
宣布的事情正常地结束了,跟 error 相同,一旦Observable
宣布了completed event
,则这个Observable
就等于中止了,以后它再也不会宣布 event 事情了。
-
next:
2.2.1 Observable 与 Sequence比较
- 1)为更好地理解,咱们能够把每一个
Observable
的实例想象成于一个 Swift 中的 Sequence:- 即一个
Observable
(ObservableType
)适当于一个序列Sequence
(SequenceType
)。 -
ObservableType.subscribe(_:)
办法其实就适当于SequenceType.generate()
- 即一个
- 2)但它们之间仍是有许多差异的:
- Swift 中的
SequenceType
是同步的循环,而Observable
是异步的。 -
Observable
目标会在有任何 Event 时分,主动将 Event 作为一个参数经过ObservableType.subscribe(_:)
宣布,并不需求运用 next 办法。
- Swift 中的
2.2.2 创立 Observable 序列
- 咱们能够经过如下几种办法来创立一个 Observable 序列
- just() 办法
(1)该办法经过传入一个默许值来初始化。
(2)下面样例咱们显式地标注出了 observable 的类型为 Observable,即指定了这个 Observable 所宣布的事情带着的数据类型必须是 Int 类型的。
let observable = Observable<Int>.just(5)
- of() 办法
(1)该办法能够承受可变数量的参数(必需求是同类型的)
(2)下面样例中我没有显式地声明出 Observable 的泛型类型,Swift 也会主动推断类型。
let observable = Observable.of("A", "B", "C")
- from() 办法
(1)该办法需求一个数组参数。
(2)下面样例中数据里的元素就会被当做这个 Observable 所宣布 event 带着的数据内容,最终效果同上面饿 of() 样例是相同的。
let observable = Observable.from(["A", "B", "C"])
- empty() 办法
该办法创立一个空内容的 Observable 序列。
let observable = Observable<Int>.never()
- never() 办法
该办法创立一个永久不会宣布 Event(也不会中止)的 Observable 序列。
let observable = Observable<Int>.never()
- error() 办法
该办法创立一个不做任何操作,而是直接发送一个过错的 Observable 序列。
enum MyError: Error {
case A
case B
}
let observable = Observable<Int>.error(MyError.A)
- range() 办法
(1)该办法经过指定起始和结束数值,创立一个以这个范围内一切值作为初始值的 Observable 序列。
(2)下面样例中,两种办法创立的 Observable 序列都是相同的。
//运用range()
let observable = Observable.range(start: 1, count: 5)
//运用of()
let observable = Observable.of(1, 2, 3 ,4 ,5)
- repeatElement() 办法
该办法创立一个能够无限宣布给定元素的 Event 的 Observable 序列(永不中止)。
let observable = Observable.repeatElement(1)
- generate() 办法
(1)该办法创立一个只要当供给的一切的判断条件都为 true 的时分,才会给出动作的 Observable 序列。
(2)下面样例中,两种办法创立的 Observable 序列都是相同的。
//运用generate()办法
let observable = Observable.generate(
initialState: 0,
condition: { $0 <= 10 },
iterate: { $0 + 2 }
)
//运用of()办法
let observable = Observable.of(0 , 2 ,4 ,6 ,8 ,10)
- create() 办法
(1)该办法承受一个 block 办法的参数,任务是对每一个过来的订阅进行处理。
(2)下面是一个简略的样例。为便利演示,这儿增加了订阅相关代码
//这个block有一个回调参数observer便是订阅这个Observable目标的订阅者
//当一个订阅者订阅这个Observable目标的时分,就会将订阅者作为参数传入这个block来履行一些内容
let observable = Observable<String>.create{observer in
//对订阅者宣布了.next事情,且带着了一个数据"hangge.com"
observer.onNext("hangge.com")
//对订阅者宣布了.completed事情
observer.onCompleted()
//因为一个订阅行为会有一个Disposable类型的回来值,所以在结束一定要returen一个Disposable
return Disposables.create()
}
//订阅测验
observable.subscribe {
print($0)
}
- deferred() 办法
(1)该个办法适当所以创立一个 Observable 工厂,经过传入一个 block 来履行推迟 Observable 序列创立的行为,而这个 block 里便是真正的实例化序列目标的地方。
(2)下面是一个简略的演示样例:
//用于符号是奇数、仍是偶数
var isOdd = true
//运用deferred()办法推迟Observable序列的初始化,经过传入的block来完结Observable序列的初始化并且回来。
let factory : Observable<Int> = Observable.deferred {
//让每次履行这个block时分都会让奇、偶数进行交替
isOdd = !isOdd
//依据isOdd参数,决定创立并回来的是奇数Observable、仍是偶数Observable
if isOdd {
return Observable.of(1, 3, 5 ,7)
}else {
return Observable.of(2, 4, 6, 8)
}
}
//第1次订阅测验
factory.subscribe { event in
print("\(isOdd)", event)
}
//第2次订阅测验
factory.subscribe { event in
print("\(isOdd)", event)
}
运转成果如下,能够看到咱们两次订阅的得到的 Observable 是不相同的:
- interval() 办法
(1)这个办法创立的 Observable 序列每隔一段设定的时刻,会宣布一个索引数的元素。并且它会一向发送下去。
(2)下面办法让其每 1 秒发送一次,并且是在主线程(MainScheduler)发送。
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
- timer() 办法
- (1) 这个办法有两种用法,一种是创立的 Observable 序列在经过设定的一段时刻后,发生仅有的一个元素。
//5秒种后宣布仅有的一个元素0
let observable = Observable<Int>.timer(5, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
- (2) 另一种是创立的 Observable 序列在经过设定的一段时刻后,每隔一段时刻发生一个元素。
//延时5秒种后,每隔1秒钟宣布一个元素
let observable = Observable<Int>.timer(5, period: 1, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
2.3 Observable订阅、事情监听、订阅毁掉
2.3.1 Observable订阅
- 有了 Observable,咱们还要运用 subscribe() 办法来订阅它,接纳它宣布的 Event。
2.3.1.1 第一种订阅办法
- (1)咱们运用 subscribe() 订阅了一个 Observable 目标,该办法的 block 的回调参数便是被宣布的 event 事情,咱们将其直接打印出来。
let observable = Observable.of("A", "B", "C")
observable.subscribe { event in
print(event)
}
运转成果如下,能够看到:
初始化 Observable 序列时设置的默许值都按顺序经过 .next 事情发送出来。
当 Observable 序列的初始数据都发送结束,它还会主动发一个 .completed 事情出来。
- (2)假如想要获取到这个事情里的数据,能够经过 event.element 得到。
let observable = Observable.of("A", "B", "C")
observable.subscribe { event in
print(event.element)
}
运转成果如下:
2.3.1.2 第二种订阅办法
- (1)RxSwift 还供给了另一个
subscribe
办法,它能够把 event 进行分类:- 经过不同的 block 回调处理不同类型的 event。(其间 onDisposed 表明订阅行为被 dispose 后的回调)
- 一起会把 event 带着的数据直接解包出来作为参数,便利咱们运用。
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
运转成果如下:
- (2)
subscribe()
办法的onNext
、onError
、onCompleted
和onDisposed
这四个回调 block 参数都是有默许值的,即它们都是可选的。所以咱们也能够只处理onNext
而不管其他的状况。
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
})
运转成果如下:
A
B
C
2.3.2 事情监听
- doOn 介绍
(1)咱们能够运用 doOn 办法来监听事情的生命周期,它会在每一次事情发送前被调用。
(2)一起它和 subscribe 相同,能够经过不同的 block 回调处理不同类型的 event。比方:
do(onNext:) 办法便是在 subscribe(onNext:) 前调用
而 do(onCompleted:) 办法则会在 subscribe(onCompleted:) 前面调用。
- 运用样例
let observable = Observable.of("A", "B", "C")
observable
.do(onNext: { element in
print("Intercepted Next:", element)
}, onError: { error in
print("Intercepted Error:", error)
}, onCompleted: {
print("Intercepted Completed")
}, onDispose: {
print("Intercepted Disposed")
})
.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
2.3.3 订阅毁掉
2.3.3.1 Observable 从创立到完结流程
- (1)一个
Observable
序列被创立出来后它不会立刻就开端被激活然后宣布 Event,而是要比及它被某个人订阅了才会激活它。 - (2)而
Observable
序列激活之后要一向比及它宣布了.error
或许.completed
的event
后,它才被完结。
2.3.3.2 dispose() 办法
- (1)运用该办法咱们能够手动撤销一个订阅行为。
- (2)假如咱们觉得这个订阅结束了不再需求了,就能够调用
dispose()
办法把这个订阅给毁掉掉,避免内存走漏。 - (3)当一个订阅行为被
dispose
了,那么之后observable
假如再宣布event
,这个现已dispose
的订阅就收不到音讯了。下面是一个简略的运用样例。
let observable = Observable.of("A", "B", "C")
//运用subscription常量存储这个订阅办法
let subscription = observable.subscribe { event in
print(event)
}
//调用这个订阅的dispose()办法
subscription.dispose()
2.3.3.13 DisposeBag
- (1)除了 dispose() 办法之外,咱们更经常用到的是一个叫 DisposeBag 的目标来管理多个订阅行为的毁掉:
- 咱们能够把一个 DisposeBag 目标看成一个垃圾袋,把用过的订阅行为都放进去。
- 而这个 DisposeBag 就会在自己快要 dealloc 的时分,对它里边的一切订阅行为都调用 dispose() 办法。
- (2)下面是一个简略的运用样例。
let disposeBag = DisposeBag()
//第1个Observable,及其订阅
let observable1 = Observable.of("A", "B", "C")
observable1.subscribe { event in
print(event)
}.disposed(by: disposeBag)
//第2个Observable,及其订阅
let observable2 = Observable.of(1, 2, 3)
observable2.subscribe { event in
print(event)
}.disposed(by: disposeBag)
2.4 AnyObserver、Binder
2.4.1 调查者(Observer)
- 调查者(Observer)的效果便是监听事情,然后对这个事情做出呼应。或许说任何呼应事情的行为都是调查者。比方:
- 当咱们点击按钮,弹出一个提示框。那么这个“弹出一个提示框”便是调查者 Observer
- 当咱们恳求一个长途的 json 数据后,将其打印出来。那么这个“打印 json 数据”便是调查者 Observer
2.4.2 创立调查者
2.4.2.1 直接在 subscribe、bind 办法中创立调查者
- 在 subscribe 办法中创立
(1)创立调查者最直接的办法便是在 Observable 的 subscribe 办法后边描述当事情发生时,需求如何做出呼应。
(2)比方下面的样例,调查者便是由后边的 onNext,onError,onCompleted 这些闭包构建出来的。
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
})
运转成果:
- 在 bind 办法中创立
(1)下面代码咱们创立一个守时生成索引数的 Observable 序列,并将索引数不断显现在 label 标签上:
//Observable序列(每隔1秒钟宣布一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "当时索引数:\($0 )"}
.bind { [weak self](text) in
//收到宣布的索引数后显现到label上
self?.label.text = text
}
.disposed(by: disposeBag)
2.4.2.2 运用 AnyObserver 创立调查者
- AnyObserver 能够用来描叙恣意一种调查者。
- 合作 subscribe 办法运用
//调查者
let observer: AnyObserver<String> = AnyObserver { (event) in
switch event {
case .next(let data):
print(data)
case .error(let error):
print(error)
case .completed:
print("completed")
}
}
let observable = Observable.of("A", "B", "C")
observable.subscribe(observer)
- 合作 bindTo 办法运用
//调查者
let observer: AnyObserver<String> = AnyObserver { [weak self] (event) in
switch event {
case .next(let text):
//收到宣布的索引数后显现到label上
self?.label.text = text
default:
break
}
}
//Observable序列(每隔1秒钟宣布一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "当时索引数:\($0 )"}
.bind(to: observer)
.disposed(by: disposeBag)
}
2.4.2.3 运用 Binder 创立调查者
(1)相较于 AnyObserver 的大而全,Binder 更专注于特定的场景。Binder 主要有以下两个特征:
不会处理过错事情
确保绑定都是在给定 Scheduler 上履行(默许 MainScheduler)
(2)一旦发生过错事情,在调试环境下将履行 fatalError,在发布环境下将打印过错信息。
- 实例2.4.2.3
//调查者
let observer: Binder<String> = Binder(label) { (view, text) in
//收到宣布的索引数后显现到label上
view.text = text
}
//Observable序列(每隔1秒钟宣布一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "当时索引数:\($0 )"}
.bind(to: observer)
.disposed(by: disposeBag)
//Observable序列(每隔1秒钟宣布一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { $0 % 2 == 0 }
.bind(to: button.rx.isEnabled)
.disposed(by: disposeBag)
2.5 自定义可绑定特点
-
有时咱们想让 UI 控件创立出来后默许就有一些调查者,而不用每次都为它们独自去创立调查者。比方咱们想要让一切的 UIlabel 都有个 fontSize 可绑定特点,它会依据事情值主动改变标签的字体大小。
-
经过对 UI 类进行扩展
这儿咱们经过对 UILabel 进行扩展,增加了一个 fontSize 可绑定特点。
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
let disposeBag = DisposeBag()
override func viewDidLoad() {
//Observable序列(每隔0.5秒钟宣布一个索引数)
let observable = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance)
observable
.map { CGFloat($0) }
.bind(to: label.fontSize) //依据索引数不断变扩大字体
.disposed(by: disposeBag)
}
}
extension UILabel {
public var fontSize: Binder<CGFloat> {
return Binder(self) { label, fontSize in
label.font = UIFont.systemFont(ofSize: fontSize)
}
}
}
- 经过对 Reactive 类进行扩展
已然运用了 RxSwift,那么更标准的写法应该是对 Reactive 进行扩展。这儿同样是给 UILabel 增加了一个 fontSize 可绑定特点。
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
let disposeBag = DisposeBag()
override func viewDidLoad() {
//Observable序列(每隔0.5秒钟宣布一个索引数)
let observable = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance)
observable
.map { CGFloat($0) }
.bind(to: label.rx.fontSize) //依据索引数不断变扩大字体
.disposed(by: disposeBag)
}
}
extension Reactive where Base: UILabel {
public var fontSize: Binder<CGFloat> {
return Binder(self.base) { label, fontSize in
label.font = UIFont.systemFont(ofSize: fontSize)
}
}
}
- RxSwift 自带的可绑定特点(UI 调查者)
其实 RxSwift 现已为咱们供给许多常用的可绑定特点。比方 UILabel 就有 text 和 attributedText 这两个可绑定特点。
extension Reactive where Base: UILabel {
/// Bindable sink for `text` property.
public var text: Binder<String?> {
return Binder(self.base) { label, text in
label.text = text
}
}
/// Bindable sink for `attributedText` property.
public var attributedText: Binder<NSAttributedString?> {
return Binder(self.base) { label, text in
label.attributedText = text
}
}
}
那么上文那个守时显现索引数的样例,咱们其实不需求自定义 UI 调查者,直接运用 RxSwift 供给的绑定特点即可。
//Observable序列(每隔1秒钟宣布一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "当时索引数:\($0 )"}
.bind(to: label.rx.text) //收到宣布的索引数后显现到label上
.disposed(by: disposeBag)
2.6 Subjects、Variables
当咱们创立一个 Observable 的时分就要预先即将宣布的数据都准备好,比及有人订阅它时再将数据经过 Event 宣布去。
但有时咱们期望 Observable 在运转时能动态地“获得”或许说“发生”出一个新的数据,再经过 Event 发送出去。比方:订阅一个输入框的输入内容,当用户每输入一个字后,这个输入框相关的 Observable 就会宣布一个带有输入内容的 Event,告诉给一切订阅者。
这个就能够运用下面即将介绍的 Subjects 来完结。
2.6.1 Subjects
2.6.1.1 Subjects 简介
-
(1)Subjects 既是订阅者,也是 Observable: 说它是订阅者,是因为它能够动态地接纳新的值。 说它又是一个 Observable,是因为当 Subjects 有了新的值之后,就会经过 Event 将新值宣布给他的一切订阅者。
-
(2)一共有四种 Subjects,别离为:
PublishSubject
、BehaviorSubject
、ReplaySubject
、Variable
。他们之间既有各自的特点,也有相同之处:
- 首要他们都是
Observable
,他们的订阅者都能收到他们宣布的新的Event
。- 直到
Subject
宣布.complete
或许.error
的Event
后,该Subject
便完结了,一起它也就不会再宣布.next
事情。- 关于那些在
Subject
完结后再订阅他的订阅者,也能收到subject
宣布的一条.complete
或.error
的event
,告诉这个新的订阅者它现已完结了。- 他们之间最大的差异只是在于:当一个新的订阅者刚订阅它的时分,能不能收到
Subject
曾经宣布过的旧Event
,假如能的话又能收到多少个。
- (3)Subject 常用的几个办法:
onNext(:)
:是 on(.next(?) 的简洁写法。该办法适当于 subject 接纳到一个 .next 事情。onError(:)
:是 on(.error(?) 的简洁写法。该办法适当于 subject 接纳到一个 .error 事情。onCompleted()
:是 on(.completed) 的简洁写法。该办法适当于 subject 接纳到一个 .completed 事情。
2.6.1.2 PublishSubject
- (1)根本介绍
PublishSubject
是最普通的Subject
,它不需求初始值就能创立。PublishSubject
的订阅者从他们开端订阅的时刻点起,能够收到订阅后Subject
宣布的新Event
,而不会收到他们在订阅前已宣布的Event
。
- (2)时序图
如下图:最上面一条是PublishSubject
。
下面两条别离表明两个新的订阅,它们订阅的时刻点不同,能够发现PublishSubject
的订阅者只能收到他们订阅后的Event
。
- 实例 2.6.1.2 :
let disposeBag = DisposeBag()
//创立一个PublishSubject
let subject = PublishSubject<String>()
//因为当时没有任何订阅者,所以这条信息不会输出到操控台
subject.onNext("111")
//第1次订阅subject
subject.subscribe(onNext: { string in
print("第1次订阅:", string)
}, onCompleted:{
print("第1次订阅:onCompleted")
}).disposed(by: disposeBag)
//当时有1个订阅,则该信息会输出到操控台
subject.onNext("222")
//第2次订阅subject
subject.subscribe(onNext: { string in
print("第2次订阅:", string)
}, onCompleted:{
print("第2次订阅:onCompleted")
}).disposed(by: disposeBag)
//当时有2个订阅,则该信息会输出到操控台
subject.onNext("333")
//让subject结束
subject.onCompleted()
//subject完结后会宣布.next事情了。
subject.onNext("444")
//subject完结后它的一切订阅(包含结束后的订阅),都能收到subject的.completed事情,
subject.subscribe(onNext: { string in
print("第3次订阅:", string)
}, onCompleted:{
print("第3次订阅:onCompleted")
}).disposed(by: disposeBag)
运转成果:
2.6.1.3 BehaviorSubject
- (1)根本介绍
BehaviorSubject 需求经过一个默许初始值来创立。
当一个订阅者来订阅它的时分,这个订阅者会当即收到 BehaviorSubjects 上一个宣布的 event。之后就跟正常的状况相同,它也会接纳到 BehaviorSubject 之后宣布的新的 event。
- (2)时序图
如下图:最上面一条是
BehaviorSubject
。
下面两条别离表明两个新的订阅,它们订阅的时刻点不同,能够发现BehaviorSubject
的订阅者一开端就能收到BehaviorSubjects
之前宣布的一个Event
。
- 实例 2.6.1.3
let disposeBag = DisposeBag()
//创立一个BehaviorSubject
let subject = BehaviorSubject(value: "111")
//第1次订阅subject
subject.subscribe { event in
print("第1次订阅:", event)
}.disposed(by: disposeBag)
//发送next事情
subject.onNext("222")
//发送error事情
subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
//第2次订阅subject
subject.subscribe { event in
print("第2次订阅:", event)
}.disposed(by: disposeBag)
运转成果:
2.6.1.4 ReplaySubject
- (1)根本介绍
ReplaySubject
在创立时分需求设置一个bufferSize
,表明它关于它发送过的event
的缓存个数。- 比方一个
ReplaySubject
的bufferSize
设置为 2,它宣布了 3 个.next
的event
,那么它会将后两个(最近的两个)event
给缓存起来。此时假如有一个subscriber
订阅了这个ReplaySubject
,那么这个subscriber
就会当即收到前面缓存的两个.next
的event
。- 假如一个
subscriber
订阅现已结束的ReplaySubject
,除了会收到缓存的.next
的event
外,还会收到那个完结的.error
或许.complete
的event
。
- (2)时序图
如下图:最上面一条是ReplaySubject(bufferSize
设为为 2)。
下面两条别离表明两个新的订阅,它们订阅的时刻点不同。能够发现ReplaySubject
的订阅者一开端就能收到ReplaySubject
之前宣布的两个Event
(假如有的话)。
- 实例 2.6.1.4 :
let disposeBag = DisposeBag()
//创立一个bufferSize为2的ReplaySubject
let subject = ReplaySubject<String>.create(bufferSize: 2)
//接连发送3个next事情
subject.onNext("111")
subject.onNext("222")
subject.onNext("333")
//第1次订阅subject
subject.subscribe { event in
print("第1次订阅:", event)
}.disposed(by: disposeBag)
//再发送1个next事情
subject.onNext("444")
//第2次订阅subject
subject.subscribe { event in
print("第2次订阅:", event)
}.disposed(by: disposeBag)
//让subject结束
subject.onCompleted()
//第3次订阅subject
subject.subscribe { event in
print("第3次订阅:", event)
}.disposed(by: disposeBag)
运转成果:
2.6.2 Variables
- 留意:因为 Variable 在之后版别中将被废弃,主张运用 Varible 的地方都改用下面介绍的 BehaviorRelay 作为代替
2.6.2.1 Variable
- (1)根本介绍
Variable
其实便是对BehaviorSubject
的封装,所以它也必需要经过一个默许的初始值进行创立。Variable
具有BehaviorSubject
的功用,能够向它的订 阅者宣布上一个event
以及之后新创立的event
。- 不同的是,
Variable
还把会把当时宣布的值保存为自己的状态。一起它会在毁掉时主动发送.complete
的event
,不需求也不能手动给Variables
发送completed
或许error
事情来结束它。- 简略地说便是
Variable
有一个value
特点,咱们改变这个value
特点的值就适当于调用一般Subjects
的onNext()
办法,而这个最新的onNext()
的值就被保存在value
特点里了,直到咱们再次修正它。Variables
本身没有subscribe()
办法,但是一切Subjects
都有一个asObservable()
办法。咱们能够运用这个办法回来这个Variable
的Observable
类型,拿到这个Observable
类型咱们就能订阅它了。
- 实例 2.6.2.1
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//创立一个初始值为111的Variable
let variable = Variable("111")
//修正value值
variable.value = "222"
//第1次订阅
variable.asObservable().subscribe {
print("第1次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
variable.value = "333"
//第2次订阅
variable.asObservable().subscribe {
print("第2次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
variable.value = "444"
}
}
留意:因为 Variable 目标在 viewDidLoad() 办法内初始化,所以它的生命周期就被限制在该办法内。当这个办法履行结束后,这个 Variable 目标就会被毁掉,一起它也就主动地向它的一切订阅者宣布 .completed 事情
运转成果:
2.6.2.2 BehaviorRelay
- 1)根本介绍
BehaviorRelay
是作为Variable
的代替者呈现的。它的本质其实也是对BehaviorSubject
的封装,所以它也必需要经过一个默许的初始值进行创立。BehaviorRelay
具有BehaviorSubject
的功用,能够向它的订阅者宣布上一个event
以及之后新创立的event
。- 与
BehaviorSubject
不同的是,不需求也不能手动给BehaviorReply
发送completed
或许error
事情来结束它(BehaviorRelay
会在毁掉时也不会主动发送.complete
的event
)。BehaviorRelay
有一个value
特点,咱们经过这个特点能够获取最新值。而经过它的accept()
办法能够对值进行修正。 (2)上面的Variable
样例咱们能够改用成BehaviorRelay
,代码如下:
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//创立一个初始值为111的BehaviorRelay
let subject = BehaviorRelay<String>(value: "111")
//修正value值
subject.accept("222")
//第1次订阅
subject.asObservable().subscribe {
print("第1次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
subject.accept("333")
//第2次订阅
subject.asObservable().subscribe {
print("第2次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
subject.accept("444")
}
}
运转成果:
- (3)假如想将新值兼并到原值上,能够经过
accept()
办法与value
特点合作来完结。(这个常用在表格上拉加载功用上,BehaviorRelay
用来保存一切加载到的数据)
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//创立一个初始值为包含一个元素的数组的BehaviorRelay
let subject = BehaviorRelay<[String]>(value: ["1"])
//修正value值
subject.accept(subject.value + ["2", "3"])
//第1次订阅
subject.asObservable().subscribe {
print("第1次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
subject.accept(subject.value + ["4", "5"])
//第2次订阅
subject.asObservable().subscribe {
print("第2次订阅:", $0)
}.disposed(by: disposeBag)
//修正value值
subject.accept(subject.value + ["6", "7"])
}
}
运转成果:
2.7 改换操作符:buffer、map、flatMap、scan等
- 改换操作指的是对原始的 Observable 序列进行一些转化,相似于 Swift 中 CollectionType 的各种转化。
2.7.1 buffer
- (1)根本介绍
buffer 办法效果是缓冲组合,第一个参数是缓冲时刻,第二个参数是缓冲个数,第三个参数是线程。
该办法简略来说便是缓存Observable
中宣布的新元素,当元素到达某个数量,或许经过了特定的时刻,它就会将这个元素调集发送出来。
- 实例 2.7.1
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
let subject = PublishSubject<String>()
//每缓存3个元素则组合起来一起宣布。
//假如1秒钟内不够3个也会宣布(有几个发几个,一个都没有发空数组 [])
subject
.buffer(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject.onNext("a")
subject.onNext("b")
subject.onNext("c")
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
}
}
运转成果:
2.7.2 window
- (1)根本介绍
window 操作符和 buffer 十分相似。不过 buffer 是周期性的将缓存的元素调集发送出来,而 window 周期性的将元素调集以 Observable 的形态发送出来。
一起 buffer 要比及元素搜集结束后,才会宣布元素序列。而 window 能够实时宣布元素序列。
- 实例 2.7.2
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
let subject = PublishSubject<String>()
//每3个元素作为一个子Observable宣布。
subject
.window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] in
print("subscribe: \($0)")
$0.asObservable()
.subscribe(onNext: { print($0) })
.disposed(by: self!.disposeBag)
})
.disposed(by: disposeBag)
subject.onNext("a")
subject.onNext("b")
subject.onNext("c")
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
}
}
运转成果:
2.7.3 map
- (1)根本介绍
该操作符经过传入一个函数闭包把本来的 Observable 序列转变为一个新的 Observable 序列。
- 实例 2.7.3
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { $0 * 10}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
10
20
30
2.7.4 flatMap
- (1)根本介绍
map
在做转化的时分容易呈现“升维”的状况。即转变之后,从一个序列变成了一个序列的序列。- 而
flatMap
操作符会对源Observable
的每一个元素应用一个转化办法,将他们转化成Observables
。 然后将这些Observables
的元素兼并之后再发送出来。即又将其 “拍扁”(降维)成一个Observable
序列。- 这个操作符对错常有用的。比方当
Observable
的元素本生具有其他的Observable
时,咱们能够将一切子Observables
的元素发送出来。
- 实例 2.7.4
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.flatMap { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
运转成果:
2.7.5 flatMapLatest
- (1)根本介绍
flatMapLatest 与 flatMap 的仅有差异是:flatMapLatest 只会接纳最新的 value 事情。
- 实例2.7.5 : 这儿咱们将上例中的 flatMap 改为 flatMapLatest
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.flatMapLatest { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
运转成果:
2.7.6 flatMapFirst
- (1)根本介绍
- flatMapFirst 与 flatMapLatest 正好相反:flatMapFirst 只会接纳开端的 value 事情。
- 该操作符能够避免重复恳求:
比方点击一个按钮发送一个恳求,当该恳求完结前,该按钮点击都不应该继续发送恳求。便可该运用 flatMapFirst 操作符。
- 实例2.7.6 :这儿咱们将上例中的 flatMapLatest 改为 flatMapFirst。
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.flatMapFirst { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
运转成果:
2.7.7 concatMap
- (1)根本介绍
concatMap 与 flatMap 的仅有差异是:当时一个 Observable 元素发送结束后,后一个Observable 才干够开端宣布元素。或许说等待前一个 Observable 发生完结事情后,才对后一个 Observable 进行订阅。
- 实例2.7.7
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.concatMap { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
subject1.onCompleted() //只要前一个序列结束后,才干接纳下一个序列
运转成果:
2.7.8 scan
- (1)根本介绍
scan 便是先给一个初始化的数,然后不断的拿前一个成果和最新的值进行处理操作。
- 实例2.7.8
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4, 5)
.scan(0) { acum, elem in
acum + elem
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果
2.7.9 groupBy
- (1)根本介绍
groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。
也便是说该操作符会将元素经过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。
- 实例2.7.9
let disposeBag = DisposeBag()
//将奇数偶数分红两组
Observable<Int>.of(0, 1, 2, 3, 4, 5)
.groupBy(keySelector: { (element) -> String in
return element % 2 == 0 ? "偶数" : "基数"
})
.subscribe { (event) in
switch event {
case .next(let group):
group.asObservable().subscribe({ (event) in
print("key:\(group.key) event:\(event)")
})
.disposed(by: disposeBag)
default:
print("")
}
}
.disposed(by: disposeBag)
运转成果:
2.8 过滤操作符:filter、take、skip等
- 过滤操作指的是从源 Observable 中选择特定的数据发送。
2.8.1 filter
- (1)根本介绍
该操作符便是用来过滤掉某些不符合要求的事情。
- 实例2.8.1
let disposeBag = DisposeBag()
Observable.of(2, 30, 22, 5, 60, 3, 40 ,9)
.filter {
$0 > 10
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
2.8.2 distinctUntilChanged
- 该操作符用于过滤掉接连重复的事情。
- 实例2.8.2
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 1, 1, 4)
.distinctUntilChanged()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
2.8.3 single
- (1)根本介绍
限制只发送一次事情,或许满意条件的第一个事情。
假如存在有多个事情或许没有事情都会宣布一个 error 事情。
假如只要一个事情,则不会宣布 error 事情。
- 实例2.8.3
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4)
.single{ $0 == 2 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
Observable.of("A", "B", "C", "D")
.single()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
2.8.4 elementAt
- 该办法完结只处理在指定方位的事情。
- 实例2.8.4
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4)
.elementAt(2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
3
2.8.5 ignoreElements
- (1)根本介绍
该操作符能够疏忽掉一切的元素,只宣布 error 或 completed 事情。
假如咱们并不关心 Observable 的任何元素,只想知道 Observable 在什么时分中止,那就能够运用 ignoreElements 操作符。
- 实例2.8.5
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4)
.ignoreElements()
.subscribe{
print($0)
}
.disposed(by: disposeBag)
运转成果:
completed
2.8.6 take
- 该办法完结仅发送 Observable 序列中的前 n 个事情,在满意数量之后会主动 .completed。
- 实例2.8.6
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4)
.take(2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
1
2
2.8.7 takeLast
- 该办法完结仅发送 Observable 序列中的后 n 个事情。
- 实例2.8.7
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4)
.takeLast(1)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
4
2.8.8 skip
- 该办法用于越过源 Observable 序列宣布的前 n 个事情。
运转成果:
3
4
2.8.9 Sample
- Sample 除了订阅源 Observable 外,还能够监督别的一个 Observable, 即 notifier 。
- 每逢收到 notifier 事情,就会从源序列取一个最新的事情并发送。而假如两次 notifier 事情之间没有源序列的事情,则不发送值。
- 实例2.8.9
let disposeBag = DisposeBag()
let source = PublishSubject<Int>()
let notifier = PublishSubject<String>()
source
.sample(notifier)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
source.onNext(1)
//让源序列接纳接纳音讯
notifier.onNext("A")
source.onNext(2)
//让源序列接纳接纳音讯
notifier.onNext("B")
notifier.onNext("C")
source.onNext(3)
source.onNext(4)
//让源序列接纳接纳音讯
notifier.onNext("D")
source.onNext(5)
//让源序列接纳接纳音讯
notifier.onCompleted()
运转成果:
1
2
4
5
2.8.10 debounce
- (1)根本介绍
- debounce 操作符能够用来过滤掉高频发生的元素,它只会宣布这种元素:该元素发生后,一段时刻内没有新元素发生。
- 换句话说便是,队列中的元素假如和下一个元素的距离小于了指定的时刻距离,那么这个元素将被过滤掉。
- debounce 常用在用户输入的时分,不需求每个字母敲进去都发送一个事情,而是稍等一下取最后一个事情。
- 实例2.8.10:
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
//定义好每个事情里的值以及发送的时刻
let times = [ [ "value": 1, "time": 0.1 ],
[ "value": 2, "time": 1.1 ],
[ "value": 3, "time": 1.2 ],
[ "value": 4, "time": 1.2 ],
[ "value": 5, "time": 1.4 ],
[ "value": 6, "time": 2.1 ]
]
//生成对应的 Observable 序列并订阅
Observable.from(times)
.flatMap { item in
return Observable.of(Int(item["value"]!))
.delaySubscription(Double(item["time"]!),
scheduler: MainScheduler.instance)
}
.debounce(0.5, scheduler: MainScheduler.instance) //只宣布与下一个距离超越0.5秒的元素
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
}
}
运转成果:
1
5
6
2.9 条件和布尔操作符:amb、takeWhile、skipWhile等
- 条件和布尔操作会依据条件发射或改换 Observables,或许对他们做布尔运算。
2.9.1 amb
- 当传入多个
Observables
到amb
操作符时,它将取第一个宣布元素或发生事情的Observable
,然后只宣布它的元素。并疏忽掉其他的Observables
。
- 实例 2.9.1
let disposeBag = DisposeBag()
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let subject3 = PublishSubject<Int>()
subject1
.amb(subject2)
.amb(subject3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject2.onNext(1)
subject1.onNext(20)
subject2.onNext(2)
subject1.onNext(40)
subject3.onNext(0)
subject2.onNext(3)
subject1.onNext(60)
subject3.onNext(0)
subject3.onNext(0)
运转成果:
1
2
3
2.9.2 takeWhile
- 该办法顺次判断 Observable 序列的每一个值是否满意给定的条件。 当第一个不满意条件的值呈现时,它便主动完结。
- 实例 2.9.2
let disposeBag = DisposeBag()
Observable.of(2, 3, 4, 5, 6)
.takeWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
2
3
2.9.3 takeUntil
- 根本介绍
- 除了订阅源
Observable
外,经过takeUntil
办法咱们还能够监督别的一个Observable
, 即notifier
。- 假如
notifier
宣布值或complete
告诉,那么源Observable
便主动完结,中止发送事情。
- 实例 2.9.3
let disposeBag = DisposeBag()
let source = PublishSubject<String>()
let notifier = PublishSubject<String>()
source
.takeUntil(notifier)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
source.onNext("a")
source.onNext("b")
source.onNext("c")
source.onNext("d")
//中止接纳音讯
notifier.onNext("z")
source.onNext("e")
source.onNext("f")
source.onNext("g")
输出成果:
a
b
c
d
2.9.4 skipWhile
- 根本介绍
- 该办法用于越过前面一切满意条件的事情。
- 一旦遇到不满意条件的事情,之后就不会再越过了。
- 实例 2.9.4
let disposeBag = DisposeBag()
Observable.of(2, 3, 4, 5, 6)
.skipWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
}
}
运转成果:
4
5
6
2.9.5 skipUntil
- 根本介绍
- 同上面的
takeUntil
相同,skipUntil
除了订阅源Observable
外,经过skipUntil
办法咱们还能够监督别的一个Observable
, 即notifier
。- 与
takeUntil
相反的是。源Observable
序列事情默许会一向越过,直到notifier
宣布值或complete
告诉。
- 实例 2.9.5
let disposeBag = DisposeBag()
let source = PublishSubject<Int>()
let notifier = PublishSubject<Int>()
source
.skipUntil(notifier)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
source.onNext(1)
source.onNext(2)
source.onNext(3)
source.onNext(4)
source.onNext(5)
//开端接纳音讯
notifier.onNext(0)
source.onNext(6)
source.onNext(7)
source.onNext(8)
//仍然接纳音讯
notifier.onNext(0)
source.onNext(9)
运转成果:
6
7
8
9
2.10 结合操作符:startWith、merge、zip等
2.10.1 startWith
- 根本介绍:
该办法会在 Observable 序列开端之前刺进一些事情元素。即宣布事情音讯之前,会先宣布这些预先刺进的事情音讯
- 图解:
- 实例 2.10.1
let disposeBag = DisposeBag()
Observable.of("2", "3")
.startWith("1")
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
1
2
3
- 实例2.10.1.1: 能够刺进多个数据
let disposeBag = DisposeBag()
Observable.of("2", "3")
.startWith("a")
.startWith("b")
.startWith("c")
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
运转成果:
c
b
a
2
3
2.10.2 merge
- 根本介绍:
该办法能够将多个(两个或两个以上的)
Observable
序列兼并成一个Observable
序列。
- 图解:
- 实例 2.10.1
let disposeBag = DisposeBag()
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
Observable.of(subject1, subject2)
.merge()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext(20)
subject1.onNext(40)
subject1.onNext(60)
subject2.onNext(1)
subject1.onNext(80)
subject1.onNext(100)
subject2.onNext(1)
运转成果:
20
40
60
1
80
100
1
2.10.3 zip
- 根本介绍:
该办法能够将多个(两个或两个以上的)
Observable
序列压缩成一个Observable
序列。
并且它会比及每个Observable
事情一一对应地凑齐之后再兼并。
- 图解:\
- 实例 2.10.1
let disposeBag = DisposeBag()
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
Observable.zip(subject1, subject2) {
"\($0)\($1)"
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)
运转成果:
1A
2B
3C
4D
- zip 常常用在整合网络恳求上:
比方咱们想一起发送两个恳求,只要当两个恳求都成功后,再将两者的成果整合起来继续往下处理。这个功用就能够经过 zip 来完结。
//第一个恳求
let userRequest: Observable<User> = API.getUser("me")
//第二个恳求
let friendsRequest: Observable<Friends> = API.getFriends("me")
//将两个恳求兼并处理
Observable.zip(userRequest, friendsRequest) {
user, friends in
//将两个信号兼并成一个信号,并压缩成一个元组回来(两个信号均成功)
return (user, friends)
}
.observeOn(MainScheduler.instance) //加这个是应为恳求在后台线程,下面的绑定在前台线程。
.subscribe(onNext: { (user, friends) in
//将数据绑定到界面上
//.......
})
.disposed(by: disposeBag)
2.10.4 combineLatest
- 根本介绍:
- 该办法同样是将多个(两个或两个以上的)Observable 序列元素进行兼并。
- 但与 zip 不同的是,每逢恣意一个 Observable 有新的事情宣布时,它会将每个 Observable 序列的最新的一个事情元素进行兼并。
- 图解:
- 实例 2.10.1
let disposeBag = DisposeBag()
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
Observable.combineLatest(subject1, subject2) {
"\($0)\($1)"
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)
运转成果:
2.10.5 withLatestFrom
- 根本介绍:
该办法将两个
Observable
序列兼并为一个。每逢self
队列发射一个元素时,便从第二个序列中取出最新的一个值。
- 图解:
- 实例 2.10.1
let disposeBag = DisposeBag()
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
subject1.withLatestFrom(subject2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("A")
subject2.onNext("1")
subject1.onNext("B")
subject1.onNext("C")
subject2.onNext("2")
subject1.onNext("D")
运转成果:
1
1
2
2.10.6 switchLatest
- 根本介绍:
switchLatest 有点像其他言语的 switch 办法,能够对事情流进行转化。
比方本来监听的 subject1,我能够经过更改 variable 里边的 value 更换事情源。变成监听 subject2。
- 图解:
- 实例 2.10.1
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.switchLatest()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
subject1.onNext("C")
//改变事情源
variable.value = subject2
subject1.onNext("D")
subject2.onNext("2")
//改变事情源
variable.value = subject1
subject2.onNext("3")
subject1.onNext("E")
运转成果:
收录自|地址