Subject
Subject는 Observable과 Observer 두가지 역할을 한다. 즉, onNext() 메소드를 통해서 Event를 발생시키는 Observable의 역할과, subscribe 메소드를 통해 Event Sequence에서 Event를 구독하여 처리할 수 있는 Observer의 역할을 모두 수행할 수 있다.
RxSwift에서는 4가지 종류의 Subject를 지원한다.
- PublishSubject
- BehaviorSubject
- ReplySubject
- Variables (Deprecated 예정)
PublishSubject
가장 일반적인 Subject이다. Observable의 특징대로 subscribe 되면 event sequence에서 event를 받으며 terminated(error 또는 completed)가 되면 더이상 event를 수신하지 않는다.
예제
let subject = PublishSubject<String>()
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("D")
subject.onNext("E")
subject.onNext("F")
// completed
subject.onCompleted()
subject.onNext("G")
subject.onNext("H")
----
D
E
F
completed
disposed
PublishSubject가 생성되고 A, B, C… 의 event sequence를 갖는다고 할 때,
observer1은 “C” event 이후에 구독을 시작한다.
따라서 D
Event 부터 수신하며 Completed Event를 수신한 이후에는 더이상 G, H는 수신하지 않는다.
BehaviorSubject
Behavior Subject의 가장 큰 특징은 initial Value를 갖는다는 것이다. 따라서 Behavior Subject를 생성시에는 반드시 초기값을 입력해야한다.
Observer측면에서 보면 구독과 동시에 initial Event를 수신한다. initial Event는 가장 최근에 발생한 Event를 의미한다.
Subject가 처음 생성되었다면 생성시 입력된 initial value를, event sequence 중간에 subscribe했다면 가장 최근의 event를 수신한다.
let subject = BehaviorSubject(value: "Initial Value")
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("D")
subject.onNext("E")
subject.onNext("F")
// completed
subject.onCompleted()
subject.onNext("G")
subject.onNext("H")
----
C
D
E
F
completed
disposed
PublishSubject 예제에서 PublishSubject를 BehaviorSubject로 변경 후의 결과이다.
observer1이 subscribe를 하면서 가장 최근에 발생한 Event C
를 가져온다는 차이점이 있다.
let subject = BehaviorSubject(value: "Initial Value")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
----
Initial Value
A
B
C
ReplaySubject
ReplaySubject는 Buffer를 갖는다. Buffer에 Event를 Queue로 저장하며 subscribe 하면 buffer에 있는 event sequence 부터 수신하기 시작한다.
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("D")
subject.onNext("E")
subject.onNext("F")
----
B
C
D
E
F
Buffer를 2로 ReplaySubject를 생성한 후 subscribe한 결과이다. 가장 최근에 발생한 B, C 를 크기가 2인 Buffer에 저장하고 있다가 subscribe가 되면 Event를 전달한다.
Buffer크기보다 이전에 발생했던 이벤트 갯수가 적으면 어떻게 될까?
let subject = ReplaySubject<String>.create(bufferSize: 5)
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("D")
subject.onNext("E")
subject.onNext("F")
----
A
B
C
D
E
F
Buffer가 가득차지 않았을 뿐, Buffer에 있는 Event들을 순서대로 구독하는데 문제가 없다.
그렇다면 subscribe 이전에 onCompleted가 발생한 경우에는 어떻게 될까?
let subject = ReplaySubject<String>.create(bufferSize: 5)
subject.onNext("A")
subject.onNext("B")
// onCompleted
subject.onCompleted()
subject.onNext("C")
// 구독 시작
let observer1 = subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print("error")
}, onCompleted: {
print("completed")
}) {
print("disposed")
}
subject.onNext("D")
subject.onNext("E")
subject.onNext("F")
----
A
B
completed
disposed
onCompleted 발생 이전의 Event들은 Buffer에 그대로 유지되며 onCompleted 까지 Event Sequence가 전달된다.
정리
Variables를 제외한 3가지 타입(Publish, Behavior, Replay)의 Subject에 대해 예제를 통해 학습했다.
각각의 Subject는 Event Sequence에 대한 처리시점에 따라 구분되어 있으며, 실제 프로젝트에 적용할 때 적절한 선택이 필요해 보인다!