OpenSource/RxSwift
RxSwift#3 Hot Observable vs Cold Observable, Subjects + Relay
malrang-malrang
2022. 9. 22. 23:47
RxSwift3 Subjects, Relay
Hot Observable vs Cold Observable
- 언제 이벤트들이 방출 되는지에 따라 Observable을 두가지로 분류할 수 있다.
- 두가지의 차이점은 다음과 같다.
- 구독할 시 데이터를 처음부터 발행 여부
- 이벤트 발생 시점
- 스트림 분기 성질
Hot Observable
- Observable을 생성하고 일정 시간이 지난 상태에서 subscribe하면 처음 데이터를 받는 것이 아닌 중간부터 방출된 데이터를 받을 수 있게된다.
- 구독 여부와 상관없이 데이터를 방출합니다.
- 데이터를 처음부터 발행하는 것이 아닌 구독 시점에서 방출되는 값을 받기 시작합니다.
- 스트림을 분기하는 성질이 있다.
- 마우스, 키보드, 시스템 이벤트와 같은 UIEvent, 타이머, 멀티 캐스팅에서 사용할 수 있다.
Cold Observable
- Observable을 구독하는 시점부터 처음 데이터부터 방출하므로 구독 이전에는 리소스를 사용하지 않는다.
- 여러곳에서 구독하면 새로운 Observable 인스턴스를 생성하며 스트림이 생성되므로 리소스 낭비가 될수 있다.
- 구독하지 않으면 데이터를 방출하지 않는다.
- 구독을 하면 데이터를 처음부터 발행하기 시작한다.
- 구독을 하게되면 별도의 스트림이 생성되게 된다.
- 웹 요청, 데이터베이스 쿼리 등에서 요청했을때 결과를 받을때 사용한다.
Subject의 종류
- Subject = Observable + Observer (와 같이 행동한다.)
- Subject는
.next
이벤트를 받고, 이런 이벤트를 수신할 때마다 subscriber에 방출한다. - Subject를 사용하면 Cold Observable을 Hot Observable로 변환할 수 있다.
- RxSwift에는 4가지 타입의 subject가 있다.
- PublishSubject: 빈상태로 시작하여 새로운 값만을 subscriber에 방출한다.
- BehaviorSubject: 하나의 초기값을 가진 상태로 시작하며, 새로운 subscriber에게 초기값 또는 최신값을 방출한다.
- ReplaySubject: 버퍼를 두고 초기화 하며, 버퍼 사이즈 만큼의 값들을 유지하면서 새로운 subscriber에게 방출한다.
- Bariable:
BehaviorSubject
를 래핑하고, 현재의 값을 상태로 보존한다. 가장 최신/초기 값만을 새로운 subscriber에게 방출한다.
PublishSubject
- PublishSubject는 subscribe된 이후부터 이벤트를 방출한다.
- 이 활동은 subscribe을 멈추거나(구독을 취소하거나),
.completed
,error
이벤트를 통해 Subject가 종료될 때 까지 지속된다.
let subject = PublishSubject<Int>()
subject.onNext(0)
let subscriptionOne = subject
.subscribe(onNext: { num in
print(num)
})
subject.on(.next(1))
subject.onNext(2)
let subscriptionTwo = subject
.subscribe({ event in
print("2)", event.element ?? event)
})
subject.onNext(3)
subscriptionOne.dispose()
subject.onNext(4)
subject.onCompleted()
subject.onNext(5)
subscriptionTwo.dispose()
let disposeBag = DisposeBag()
subject
.subscribe {
print("3)", $0.element ?? $0)
}
.disposed(by: disposeBag)
subject.onNext(9999)
/* Prints:
1
2
3
2) 3
2) 4
2) completed
3) completed
*/
- 종료되었을 때 존재하는 구독자 뿐만 아니라 이후에 구독한 subscriber에게도 종료 이벤트를 보내준다.
- 시간에 민감한 데이터를 모델링 할 때 사용한다.(subscribe되기 이전의 값이 필요 없는 경우)
BehaviorSubject
- PublishSubject 와 비슷하지만 초기 이벤트를 가진 Subject다.
- subscribe 될때 가장 최신의 .next 이벤트를 전달한다.
- BehaviorSubject는 항상 최신의 .next 이벤트를 방출하기 때문에 초기값 없이는 만들수 없다. 초기값이 없다면 PublishSubject를 사용하자!
let subject = BehaviorSubject<Int>(value: 0)
let disposeBag = DisposeBag()
subject.onNext(1)
subject.subscribe {
print("1)", $0.element ?? $0)
}.disposed(by: disposeBag)
subject.onError(TestError.test)
subject.subscribe {
print("2)", $0.element ?? $0)
}.disposed(by: disposeBag)
/* Prints:
1) 1
1) error(test)
2) error(test)
*/
- 항상 최신 데이터로 채워 놓아야 하는 경우에 사용한다.(유저 프로필)
ReplaySubject
- ReplaySubject는 bufferSize갯수의 이벤트를 저장해 subscribe될 때 저장된 이벤트를 모두 방출한다.
let subject = ReplaySubject<Int>.create(bufferSize: 3)
let disposeBag = DisposeBag()
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.subscribe {
print("1)", $0.element ?? $0)
}.disposed(by: disposeBag)
subject.subscribe {
print("2)", $0.element ?? $0)
}.disposed(by: disposeBag)
/* Prints:
1) 2
1) 3
1) 4
2) 2
2) 3
2) 4
*/
- 최신의 여러 값들을 보여주고 싶을때 사용한다 (최근 검색어)
Relay
- Subject와 다르게 error나 complete를 통해 완전 종료될수 없다.
- subscribe 하고 싶을때는 asObservable을 사용할수 있다.
PublishRelay
- PublishRelay를 래핑해서 가지고 있는다.
- Subject는
.completed
나.error
를 받으면 subscribe이 종료된다. 하지만 PublishRelay는 dispose되기 전까지 게속 작동하기 때문에 UIEvent에서 사용하기 적절하다.
BehaviorRelay
- BehaviorSubject를 래핑해서 가지고 있는다.
.value
를 사용해 현재의 값을 꺼낼 수 있다. (get-only 프로퍼티)- value를 변경하기 위해서
.accept()
를 사용한다.
참고한 문서및 자료
https://github.com/fimuxd/RxSwift/blob/master/Lectures/03_Subjects/Ch3.%20Subjects.md
https://okanghoon.medium.com/rxswift-2-observable-subject-relay-8fcd9b01913d