03. RxSwift (3) ———— Concept of Subjects

It will take about 5 minutes to finish reading this article.

Subjet is the bridge between observable and Observer. A Subject is both an Observable and an Observer. It can both emit events and listen for events. This is similar to RAC.

1. PublishSubject

When you subscribe to a PublishSubject, you can only receive events that occur after you subscribe to it. subject.onNext() emits onNext event, corresponding to onError() and onCompleted() events. PublishSubject is both an Observable and an Observer.

As shown in the image above,
The first line is a PublishSubject, the second and third lines are subscribers, the upward arrow indicates that the subscriber subscribes to the Subject, and the downward arrow indicates that the Subject sends events.

The first subscriber doesn’t subscribe until after the 1 event has been sent, so it won’t receive the 1 event, it will receive the 2.3 event. The second subscriber subscribes after the 2 event has been sent, so it will only receive the 3 event.

The next event of PublishSubject will only be sent to subscribers who are currently subscribed to this subject. New subscribers will not receive events sent before subscribing.

After the Subject terminates, if you subscribe again, its termination event will be sent to subsequent subscribers. This is true for all subjects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func example12() {
let subject = PublishSubject<String>()

subject.onNext("1")

let subscriptionOne = subject.subscribe(onNext: { (element) in
print("Subscriber one: " + element)
}).disposed(by: disposeBag)

subject.on(.next("2"))

let subscriptionTwo = subject.subscribe(onNext: { (element) in
print("Subscriber two: " + element)
}).disposed(by: disposeBag)

subject.onNext("3")
}
//Results:
Subscriber one: 2
Subscriber one: 3
Subscriber Two: 3

2. BehaviorSubject

When you subscribe to a BehaviorSubject, you will receive the last event before subscribing. BehaviorSubject is actually similar to PublishSubject, except that it will send the latest next event to new subscribers.

As shown in the figure below, the first line is a BehaviorSubject, the second and third lines are subscribers, the upward arrow indicates that the subscriber subscribes to the Subject, and the downward arrow indicates that the Subject sends events. The first subscriber subscribes to the subject after event 1, and it will immediately receive the most recent next event, that is, events after 1. will be received normally.

The second subscriber subscribes to the subject after event 2, and it will immediately receive the most recent next event, that is, events after 2. will be received normally.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func example13 () {
let subject = BehaviorSubject(value: "1")

subject.onNext("1")

subject.subscribe(onNext: { (element) in
print("Subscriber one: " + element)
}).disposed(by: disposeBag)

subject.on(.next("2"))
subject.on(.next("3"))

subject.subscribe(onNext: { (element) in
print("Subscriber two: " + element)
}).disposed(by: disposeBag)

subject.onNext("4")
}
//The execution results are as follows:
Subscriber one: 1
Subscriber one: 2
Subscriber one: 3
Subscriber Two: 3
Subscriber one: 4
Subscriber Two: 4

3. ReplaySubject

Replay subjects can specify a buffer size, which will cache the recently sent events. The size of the buffer size is the number of cached events. When there is a new subscriber, it will send the cached events to the new subscriber.

As shown in the above image,

The first line is a ReplaySubject with a buffer size of 2, which caches the two most recent events. The second and third lines are subscribers. The upward arrow indicates that the subscriber subscribes to the Subject, and the downward arrow indicates that the Subject sends events.

The first subscriber is subscribed at the beginning, so it can receive,1,2,3 events

The second subscriber subscribes after event 2. Because the buffer size of ReplaySubject is 2, the second subscriber will immediately receive the cached events 1 and 2. 3 events are received normally.

Points to note:

The cache of ReplaySubject is cached in the memory. Therefore, if the ReplaySubject sends pictures, the buffer size cannot be set too large, which can easily cause memory pressure. The same goes for sending an array. Therefore, you must pay attention to the content pressure and type here, and do not set the buffer size too large.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func example14() {
let subject = ReplaySubject<String>.create(bufferSize: 2)

subject.onNext("1")
subject.onNext("2")
subject.onNext("3")

subject.subscribe(onNext: { (element) in
print("Subscriber one: " + element)
}).disposed(by: disposeBag)
}
//Results of the
Subscriber One: 2
Subscriber One: 3