이번에는 RxSwift의 Subject에 대해서 알아볼 것이다.
Subject는 무엇이고, 어떻게 만들어 사용하는 건지 알아보자.
이전에 Observable에 대해서 배우긴 했지만, 실제 필요한 것은 실시간으로 Observable에 값을 추가하고 Subscribe이 방출하도록 하는 것이다.
즉, Subject는 "Observable 이자 Observer"이다.
PublishSubject
빈 상태로 시작하여 새로운 값만 subscriber에 방출하는데, 구독된 순간 새로운 이벤트 수신을 알릴 때 용이하다.
첫 번째 subscriber는 구독한 이후에 처음으로 발생한 2, 3을 받는다.
두 번째 subscriber는 1,2가 방출된 다음에 구독했기 때문에 구독한 이후에 처음 발생한 3을 받는다.
BehaviorSubject
하나의 초깃값을 가진 상태로 시작하여 새로운 subscriber에게 초깃값 또는 최신값을 방출한다.
마지막 Next 이벤트를 새로운 구독자에게 넘겨주는 것 외에 PublishSubject와 동일하다.
ReplaySubject
버퍼를 두고 초기화하며 버퍼 사이즈만큼 값을 유지하면서 새로운 subscriber에게 방출한다.
위에서 ReplaySubject 버퍼 사이즈를 2라고 두었다.
첫 번째 subscriber는 처음부터 구독하기 때문에 그대로 다 받았고, 두 번째 subscriber는 뒤늦게 구독했음에도 버퍼 사이즈만큼 값을 받은 것이다.
여기서 주의해야 할 점은 버퍼는 메모리를 차지하기 때문에 이미지나 배열 등 메모리를 크게 차지하는 형태로 버퍼를 갖는 것은 좋지 않다.
let publishSubject = PublishSubject<String>()
publishSubject.asObserver().onNext("1")
let subscriber1 = publishSubject // subscriber1 구독 전 1은 방출되지 않음
.subscribe(onNext: {
print("subscriber1 : \($0)")
})
publishSubject.onNext("2") // 방출
publishSubject.on(.next("3")) // 방출
subscriber1.dispose() // subscriber1 종료
let subscriber2 = publishSubject // subscriber2 구독 전 1,2,3은 방출되지 않음
.subscribe(onNext: {
print("subscriber2 : \($0)")
})
publishSubject.onNext("4") // 방출
publishSubject.onCompleted() // Subject 종료
publishSubject.onNext("5") // Subject 종료되었으므로 방출되지 않음
subscriber2.dispose() // subscriber2 종료
// print
// subscriber1 : 2
// subscriber1 : 3
// subscriber2 : 4
▼ MarbleDiagram
let disposeBag = DisposeBag()
enum SubjectError: Error {
case error1
}
let behaviorSubject = BehaviorSubject<String>(value: "0")
behaviorSubject.onNext("1")
behaviorSubject.subscribe { // 1 이후에 구독했지만, 1 전달 받음
print("subscriber1 : \($0)")
}
.disposed(by: disposeBag)
behaviorSubject.onError(SubjectError.error1)
behaviorSubject.subscribe { // error 이후에 구독했지만, error 전달 받음
print("subscriber2 : \($0)")
}
.disposed(by: disposeBag)
let value = try? behaviorSubject.value() // 가장 최신 값을 뽑아냄
print(value)
// print
// subscriber1 : next(1)
// subscriber1 : error(error1)
// subscriber2 : error(error1)
// nil
▼ MarbleDiagram
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
replaySubject.onNext("1")
replaySubject.onNext("2")
replaySubject.onNext("3")
replaySubject.subscribe { // 1,2,3 이후에 구독했지만 버퍼사이즈 2만큼인 2와 3을 받음
print("subscriber1 : \($0)")
}
.disposed(by: disposeBag)
replaySubject.subscribe { // subscriber1과 동일
print("subscriber2 : \($0)")
}
.disposed(by: disposeBag)
replaySubject.onNext("4")
replaySubject.onError(SubjectError.error1)
replaySubject.dispose() // Subject 종료
replaySubject.subscribe { // Subject 종료 후 구독했으므로 에러 방출
print("subscriber3 : \($0)")
}
.disposed(by: disposeBag)
// print
// subscriber1 : next(2)
// subscriber1 : next(3)
// subscriber2 : next(2)
// subscriber2 : next(3)
// subscriber1 : next(4)
// subscriber2 : next(4)
// subscriber1 : error(error1)
// subscriber2 : error(error1)
// subscriber3 : error(Object `RxSwift.(unknown context at $105b9aef0).ReplayMany<Swift.String>` was already disposed.)
▼ MarbleDiagram
이렇게 총 3종류의 Subject를 알아보았다.
Observable에 대해서는 이렇게 마무리하고, 다음부터는 Operator(Filtering Operator)를 파헤쳐 보자.