RxSwift - Subject 阅读笔记

什么是 subject

Subject 同时扮演 observableobserver 的角色

RxSwift 提供了四种类型的 subject

Subject Description
PublishSubject 没有默认值,只发送订阅之后的事件
BehaviorSubject 有默认值,会发送默认值或最新的一次事件给订阅者
ReplaySubject 没有默认值,自带缓存,有订阅时会将缓存中的事件全部发给订阅者
Variable 将变量做为一个 subject 和 BehaviorSubject 类似

Subject 使用

PublishSubjects

首先来看一张图

RxSwift - Subject 阅读笔记_第1张图片
PublishSubject
  • 第一条线表示整个事件序列
  • 第二条线表示第一个订阅者在事件 A 发生之后订阅了该事件序列,因此第一个订阅者可以接收到 B 和 C
  • 第三条线表示第二个订阅者在事件 B 之后订阅了该事件序列,因此它只能接收到 C

代码演示,大概就是

let subject = PublishSubject()
let bag = DisposeBag()
subject.onNext("A")
    
let subscriptionOne = subject.subscribe({ (event) in
    print("1) ", event.element ?? event)
})
    
subject.on(.next("B"))
    
let subscriptionTwo = subject.subscribe({ (event) in
    print("2) ", event.element ?? event)
})

控制台的打印结果为

1)  B
1)  C
2)  C

此时如果取消第一个订阅,在最后添加如下代码

subscriptionOne.dispose()
subject.on(.next("D"))

此时就只有第二个订阅者可以订阅到事件 D。

当一个 PublishSubject 接收到一个 .completed 或者 .error 事件,它会发送这些终止事件给新的订阅者并且不再发送 .next 事件。然而事实上,它会将终止事件传递给未来的订阅者。

subject.onCompleted()
subject.onNext("E")
    
subscriptionTwo.dispose()
let disposeBag = DisposeBag()
    
subject.subscribe({
    print("3) ", $0.element ?? $0)
})
.disposed(by: disposeBag)
    
subject.onNext("?")

打印结果为

2)  completed
3)  completed

BehaviorSubjects

BehaviorSubjectSubjectSubject 工作方式及其类似,区别就在于,BehaviorSubject 会发送最新的 .next 事件给新的订阅者。

RxSwift - Subject 阅读笔记_第2张图片
BehaviorSubject

由于 BehaviorSubject 总是发出最新的事件,所以必须在创建时给予默认值

enum MyError: Error {
    case anError
}

func print(label: String, event: Event) {
    print(label, event.element ?? event.error ?? event)
}
  1. 自定义了一个错误类型
  2. 创建了一个打印函数,方便打印订阅的事件
let subject = BehaviorSubject(value: "Initial value")
let disposeBag = DisposeBag()
    
subject.subscribe({
    print(label: "1)", event: $0) 
})
.disposed(by: disposeBag)

声明了一个带有默认值的 BehaviorSubject 实例,之后订阅它,打印结果为

1) Initial value

由于没有新的事件,因此会将创建实例时的默认值作为最新的事件传递给订阅者。此时,如果我们在订阅之前,通过 onNext 发送一个事件,那么订阅者将会订阅到该事件,而不会接收到默认事件。

在第一次订阅之后,添加如下代码,结果会是什么呢?

subject.onError(MyError.anError)    
subject.subscribe({
    print(label: "2)", event: $0)
})

.error 事件被订阅到两次,每个订阅者都收到了这个 .error 事件。

BehaviorSubject 在我们想要展示一个包含最近数据的 view 时将非常有用,但,如果你想展示的不止是最近的数据,你想展示更多以往数据,那么,ReplaySubject 将会是你想要的。

ReplaySubject

ReplaySubject 会暂存最新发送的事件到 cache 或者 buffer 中,之后会将这些暂存的事件发送个新的订阅者。下图描述了一个 buffer size 为 2 的 ReplaySubject。第一个订阅者(中间)已经订阅了 ReplaySubject (顶部)因此它接收到了所有事件。第二个订阅者(底部)在 B 事件之后订阅,由于存储了之前的两个事件,因此第二个订阅者也能接收到所有事件。

RxSwift - Subject 阅读笔记_第3张图片
ReplaySubject

ReplaySubject 的使用需要谨慎考虑内存问题

用法实例

let subject = ReplaySubject.create(bufferSize: 2)
let disposeBag = DisposeBag()
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
subject
    .subscribe({
        print(label: "1) ", event: $0)
    })
    .disposed(by: disposeBag)
subject
    .subscribe({
        print(label: "2) ", event: $0)
    })
    .disposed(by: disposeBag)

首先,定义了一个 Buffer size 为 2 的 ReplaySubject,发送三个 .next 事件,之后,用两个订阅者订阅这个事件。订阅者 1) 和订阅者 2) 都接收到了缓存起来的事件 2 和事件 3

1)  2
1)  3
2)  2
2)  3

接下来添加如下代码

subject.onNext("4")
subject
    .subscribe({
        print(label: "3) ", event: $0)
    })
    .disposed(by: disposeBag)

发送新的事件 4 并新增一个订阅。这时订阅者 1) 和订阅者 2) 也能够接收到事件 4,而新增的订阅者 3) 就只能接收到事件 34 了。

如果在事件 4 之后,订阅 3) 建立之前,我们添加如下 .error 事件

subject.onError(MyError.anError)

这时,订阅者 1) 2) 也都将收到这个这个 .error 事件。订阅者 3) 将接收到事件 3 4 以及 .error 事件。在接收到终止事件之前,ReplaySubject 都会一直将 buffer 的内容发送给订阅者。

Variables

VariableBehaviorSubject 类似,Variable 的创建包含一个初始值,并且返回最新的事件或者初始值给新的订阅者。为了订阅一个 Variable 需要调用 asObservable()

var variable = Variable("Initial value")
let disposeBag = DisposeBag()
    
variable.value = "New initial value"
    
variable
    .asObservable()
    .subscribe({
        print(label: "1)", event: $0)
    })
    .addDisposableTo(disposeBag)
    
variable.value = "1"
    
variable
    .asObservable()
    .subscribe({
        print(label: "2)", event: $0)
    })
    .addDisposableTo(disposeBag)
    

variable.value = "2"

结果为

1) New initial value
1) 1
2) 1
1) 2
2) 2

你可能感兴趣的:(RxSwift - Subject 阅读笔记)