/RxSwift
[RxSwift] “Hot” Observables, “Cold” Observables
아렉스_Arex
2025. 2. 28. 00:32
반응형
2025.02.25 - [/RxSwift] - [RxSwift] RxSwift 란 무엇일까 ?
2025.02.26 - [/RxSwift] - [RxSwift] RxSwift를 이루는 Observable과 Observer
안녕하세요 아렉스입니다 :>
오늘은 Observable의 종류 두가지, Hot Observable과 Cold Observable에 대해서 얘기하겠습니다.
1. Hot Observable과 Cold Observable이란?
RxSwift에서 Observable은 데이터를 방출하는 방식에 따라 Cold Observable과 Hot Observable로 나뉩니다. 이 두 가지의 차이를 이해하면, RxSwift에서 데이터를 다루는 방식을 보다 효과적으로 활용할 수 있습니다.
2. Cold Observable
Cold Observable은 구독(Subscribe)하기 전까지 이벤트를 방출하지 않는 Observable입니다.
즉, 각 구독자(Subscriber)마다 독립적인 데이터 스트림을 받습니다.
특징
- 구독을 해야만 데이터를 받을 수 있음.
- 구독할 때마다 새로운 데이터를 생성.
- 네트워크 요청, 파일 읽기 등의 경우에 적합.
예제
import RxSwift
let observable = Observable<Int>.create { observer in
print("데이터 생성 시작")
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onCompleted()
return Disposables.create()
}
// ✅ 구독 1
let subscription1 = observable.subscribe(onNext: { value in
print("구독 1: \(value)")
})
// // ✅ 구독 2
let subscription2 = observable.subscribe(onNext: { value in
print("구독 2: \(value)")
})
// ✅ 실행결과
// 구독1: red
// 구독1: blue
// 구독1: yellow
// 구독2: red
// 구독2: blue
// 구독2: yellow
3. Hot Observable
Hot Observable은 구독 여부와 관계없이 데이터를 지속적으로 방출하는 Observable입니다.
따라서 새로운 구독자는 과거 이벤트를 받을 수 없고, 방출되는 시점 이후의 데이터만 수신합니다.
특징
- 구독 전에 발생한 이벤트는 받을 수 없음.
- 모든 구독자가 동일한 데이터를 공유.
- UI 이벤트(Button Tap), 타이머, 센서 데이터 등의 경우에 적합.
예제 (PublishSubject 사용)
import RxSwift
let subject = PublishSubject<String>()
// ✅ 구독1
let subscription1 = subject.subscribe(onNext: { value in
print("구독 1: \(value)")
})
subject.onNext("A")
subject.onNext("B")
// ✅ 구독2
let subscription2 = subject.subscribe(onNext: { value in
print("구독 2: \(value)")
})
subject.onNext("C")
subject.onNext("D")
// ✅ 실행결과
// 구독1: A
// 구독1: B
// 구독1: C
// 구독2: C
// 구독1: D
// 구독2: D
4. Cold Observable을 Hot Observable로 변환하기
하지만 여러 구독자가 단 하나의 구독의 이벤트(요소)를 공유하도록 하려면 어떻게 해야 할까요 ?
기본적으로 Observable은 Cold Observable이지만, share()를 사용하면 Hot Observable처럼 동작하도록 만들 수 있습니다.
예제
// ✅ 1초 단위로 이벤트 방출
let interval = Observable<Int>
.interval(.seconds(1), scheduler: MainScheduler.instance)
.share(replay: 1)
// ✅ 구독 1
interval
.subscribe(onNext: { data in
print("구독: \(data)")
})
.disposed(by: self.diposeBag)
// ✅ 구독 2
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
interval
.subscribe(onNext: { data in
print("구독2: \(data)")
})
.disposed(by: self.diposeBag)
})
// ✅ 실행결과
// 구독: 0
// 구독: 1
// 구독: 2
// 구독: 3
// 구독: 4
// 구독2: 4 <-- 구독이 늦어져서 4부터 받음
// 구독: 5
// 구독2: 5
// 구독: 6
// 구독2: 6
// 구독: 7
// 구독2: 7
// 구독: 8
// 구독2: 8