티스토리 뷰

RxSwift의 Cold vs Hot 개념 정리

iOS 개발을 하다 보면 비동기 작업을 다룰 일이 많다.
예를 들어, 네트워크 요청을 하거나, 사용자의 버튼 탭 이벤트를 처리하고,
그에 따른 화면 UI를 업데이트하는 작업은 거의 매일 마주치는 일이다.

이럴 때 자주 쓰게 되는 것이 Observable이다.
그런데 개발을 하다 보면 다음과 같은 의문이 생길 때가 있다.

“같은 Observable인데 구독할 때마다 동작이 다르네?”
“subscribe만 했을 뿐인데 왜 두 번 요청이 나가지?”

이런 현상은 대부분 Observable이 Cold인지 Hot인지에 따라 달라지는 동작 때문이다.
이번 글에서는 RxSwift의 Cold Observable과 Hot Observable의 차이를 명확하게 짚어보고,
실제 iOS 프로젝트에서 어떻게 활용하면 좋을지도 함께 정리해보자.


Cold Observable: 구독할 때마다 새롭게 시작된다

Cold Observable은 말 그대로 ‘차가운’, 아직 시작되지 않은 상태를 의미한다.
이 옵저버블은 누군가가 구독하기 전까지는 아무 일도 하지 않는다.
그리고 구독이 발생하면 그때 비로소 동작을 시작한다.

쉽게 말하면, 녹화 방송을 틀어주는 것과 같다.
각 구독자는 자기만의 타이밍으로 방송을 처음부터 보기 시작한다.

예제

let coldObservable = Observable<Int>.create { observer in
    print("📡 새로운 스트림 시작")
    observer.onNext(Int.random(in: 1...100))
    observer.onCompleted()
    return Disposables.create()
}

coldObservable.subscribe(onNext: { print("👤 구독자 A: \($0)") })
coldObservable.subscribe(onNext: { print("👤 구독자 B: \($0)") })

출력 예시

📡 새로운 스트림 시작
👤 구독자 A: 42
📡 새로운 스트림 시작
👤 구독자 B: 91
  • subscribe가 발생할 때마다 새로운 데이터 스트림이 만들어진다.
  • 네트워크 요청, 파일 읽기, 데이터베이스 쿼리 등 대부분의 작업은 Cold Observable로 표현된다.

Hot Observable: 이미 방송 중인 상태

Hot Observable은 누군가가 구독하기 전에도 이미 데이터가 흘러가고 있는 상태다.
즉, 실시간 생방송을 생각하면 된다.
방송이 시작된 후에 들어오면, 그 시점 이후의 데이터만 받을 수 있다.

Hot Observable을 직접 만들기 위해서는 보통 Subject를 사용한다.
가장 기본적인 예는 PublishSubject이다.

예제

let subject = PublishSubject<String>()

subject.onNext("🔴 방송 시작 전") // 구독자가 없기 때문에 무시된다

subject.subscribe(onNext: { print("👤 A: \($0)") })
subject.onNext("📺 방송 1")

subject.subscribe(onNext: { print("👤 B: \($0)") })
subject.onNext("📺 방송 2")

출력 예시

👤 A: 📺 방송 1
👤 A: 📺 방송 2
👤 B: 📺 방송 2
  • 구독자 A는 방송 1부터 받았고,
  • 구독자 B는 방송 2부터 받았다.

이처럼 구독 타이밍에 따라 받는 데이터가 다르다는 것이 Hot Observable의 특징이다.


Cold와 Hot, 언제 어떻게 써야 할까?

iOS 개발에서는 두 가지 타입의 Observable을 모두 자주 만나게 된다.
중요한 건 상황에 맞게 선택하고, 필요하다면 Cold를 Hot으로 변환해서 써야 한다는 점이다.

상황 Cold Observable Hot Observable

네트워크 요청
버튼 탭 이벤트
센서 스트림, NotificationCenter
캐시된 데이터 재사용 ✅ (share 필요)

Cold를 Hot처럼 바꾸려면?

RxSwift에서는 share() 또는 multicast() 연산자를 통해
Cold Observable을 Hot처럼 공유할 수 있다.

예를 들어, 타이머처럼 반복되는 이벤트를 여러 구독자가 함께 보려면 아래와 같이 쓴다.

let shared = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .take(3)
    .share()

shared.subscribe(onNext: { print("👤 A: \($0)") })

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    shared.subscribe(onNext: { print("👤 B: \($0)") })
}

출력 예시

👤 A: 0
👤 A: 1
👤 A: 2
👤 B: 2

share() 덕분에 Cold였던 Observable이 Hot처럼 공유되는 것을 확인할 수 있다.


마무리: 지금 내 Observable은 어떤 타입일까?

RxSwift를 쓰다 보면 구독자가 여러 명일 때, 의도치 않게 네트워크 요청이 중복되거나,
이벤트를 놓치는 문제가 발생할 수 있다.

이럴 때 Observable이 Cold인지, Hot인지 구분하고
필요하다면 share()나 Subject로 조정해주는 것이 중요하다.

지금 작성 중인 Observable은 구독할 때마다 새로 실행되고 있는가?
아니면 이미 흘러가는 이벤트를 받아야 하는 상황인가?

이 질문을 기준으로 Cold와 Hot을 구분해보자.
RxSwift의 흐름이 더 명확해지고, 디버깅도 훨씬 쉬워질 것이다.


다음 포스팅에서는 BehaviorSubject, ReplaySubject, 그리고 share(replay:scope:)를 활용해
데이터 캐싱 및 이벤트 공유를 어떻게 구성할 수 있는지도 다뤄볼 예정이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
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
26 27 28 29 30
글 보관함