안녕하세요, iOS 개발하는 루피입니다.
오늘은 ReactiveX 공식문서 Subject 부분을 공부 해보려고 합니다. 그러면 지금부터 시작해 보도록 하겠습니다!!
공식문서 바로가기!!!!
Subject란?
Subject는 Observable이면서 동시에 Observer 역할도 할 수 있는 일종의 다리 같은 존재라고 합니다. "Observable처럼 값을 방출할 수도 있고, Observer처럼 다른 Observable들을 구독할 수도 있다고 합니다."
Subject는 onNext, onError, onCompleted 등의 메서드를 사용하여 데이터를 방출하고, 이벤트를 발생시키며, 다른 Observable과도 상호작용할 수 있어요. 이처럼 Subject는 데이터를 받기도 하고, 다시 내보내기도 하죠. 그래서 Subject는 언제든지 새로운 값을 방출하거나, 구독된 Observable의 값을 받아서 재방출할 수 있다고 합니다!!
Subject의 동시성 문제
Subject를 사용할 때 주의할 점이 있다고 합니다!! 멀티 스레드 환경에서의 Subject 사용 시 Observer 측면이 스레드 안전하지 않다고 합니다. subscribe()는 스레드 안전하지만, 여러 스레드에서 onNext, onError, onCompleted를 동시에 호출하면 예상하지 못한 상태가 발생할 수 있어요. 이럴 때, 대부분의 RxSwift 구현체에서는 ToSerialized라는 특별한 연산자를 제공해 observer 측면도 스레드 안전하게 만들어준다고 합니다. 그렇다고 하는데 아직 잘 모르겠네요 ….ㅎㅎ 우선 넘어가고 다음 기회에 다시 한번 공부해보도록 하겠습니다!
Subject 종류
Subject는 다양한 상황에 맞게 네 가지 종류로 나누어져 있어요. 각 종류는 특정한 시나리오에 적합하도록 설계되어 있으니, 사용 상황에 따라 적절한 Subject를 선택해야 해요.
1. PublishSubject
- 구독 이후에 방출된 아이템만 observer에게 전달합니다.
- 구독자가 생기기 전의 이벤트는 받을 수 없어요.
- 가장 일반적인 형태로 생각할 수 있고, 다수의 구독자가 동일한 Subject의 이벤트를 받을 수 있어요.


코드
import RxSwift
let disposeBag = DisposeBag()
// PublishSubject 예시
let publishSubject = PublishSubject<String>()
publishSubject.onNext("Before subscription") // 방출되지 않음
publishSubject
.subscribe(onNext: { value in
print("PublishSubject received: \(value)")
})
.disposed(by: disposeBag)
publishSubject.onNext("After subscription") // 방출됨
// PublishSubject received: After subscription
2. BehaviorSubject
- 구독하는 순간 가장 최근에 방출된 값을 즉시 받게 됩니다.
- 그리고 그 이후에 방출되는 모든 값을 구독자가 받을 수 있어요.
- 항상 가장 최근의 값 하나를 저장하고 있기 때문에, state와 비슷하게 사용할 수 있어요.


코드
import RxSwift
let disposeBag = DisposeBag()
// BehaviorSubject 예시
let behaviorSubject = BehaviorSubject(value: "Initial value")
behaviorSubject
.subscribe(onNext: { value in
print("BehaviorSubject received: \(value)")
})
.disposed(by: disposeBag)
behaviorSubject.onNext("New value")
// BehaviorSubject received: Initial value
// BehaviorSubject received: New value
Q ) State와 비슷하게 사용할 수 있다는 말이 무슨 말인가 ???
BehaviorSubject가 항상 "현재 상태"를 가지고 있고, 그 상태를 언제든지 구독자에게 전달할 수 있기 때문이에요.
BehaviorSubject의 특징
- BehaviorSubject는 초기값(initial value)을 갖고 시작합니다.
- 이후에 새로운 값이 방출되면, 그 값을 항상 가장 최신의 값으로 저장합니다.
- subscriber가 생기면, BehaviorSubject는 저장된 최신값을 즉시 전달합니다.
- 그리고 그 이후에 방출되는 값도 계속 전달합니다.
이러한 특성은 state와 매우 유사해요. 앱의 상태를 관리할 때 우리는 보통 현재 상태를 저장하고, 상태가 변경되면 그 변경 사항을 구독자에게 알려주잖아요? BehaviorSubject는 이러한 동작을 아주 간단하게 구현할 수 있도록 도와줘요.
코드
import RxSwift
// DisposeBag 생성
let disposeBag = DisposeBag()
// BehaviorSubject를 마치 상태처럼 사용
let state = BehaviorSubject(value: "Idle")
// 구독자 추가
state
.subscribe(onNext: { currentState in
print("Current State: \\(currentState)")
})
.disposed(by: disposeBag)
// 새로운 상태 방출
state.onNext("Loading")
state.onNext("Completed")
// Current State: Idle
// Current State: Loading
// Current State: Completed
3. ReplaySubject
- 구독자에게 모든 방출된 값을 재생합니다.
- 즉, 구독 시점과 관계없이 이전에 방출된 모든 아이템 을 전달받을 수 있어요.
- 버퍼 크기를 지정하여 메모리 사용을 조절할 수 있고, 구독자에게 재생할 항목의 수나 시간을 제한할 수도 있어요.

코드
import RxSwift
let disposeBag = DisposeBag()
// ReplaySubject 예시
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
// 사이즈를 3으로 설정할 경우 3개가 다 출력 된다.
replaySubject.onNext("First value")
replaySubject.onNext("Second value")
replaySubject.onNext("Third value")
replaySubject
.subscribe(onNext: { value in
print("ReplaySubject received: \(value)")
})
.disposed(by: disposeBag)
// ReplaySubject received: Second value
// ReplaySubject received: Third value
4. AsyncSubject
- 소스 Observable이 완료되면, 그때까지 방출된 가장 마지막 값만 전달합니다.
- 완료 이벤트가 발생하기 전까지는 어떤 값도 방출하지 않아요.
- 특정 시점에 하나의 결과를 전달해야 하는 경우에 유용합니다.


코드
import RxSwift
let disposeBag = DisposeBag()
// AsyncSubject 예시
let asyncSubject = AsyncSubject<String>()
asyncSubject
.subscribe(onNext: { value in
print("AsyncSubject received: \(value)")
})
.disposed(by: disposeBag)
asyncSubject.onNext("First value")
asyncSubject.onNext("Second value")
asyncSubject.onCompleted() // 마지막 값인 "Second value"만 방출됨
// AsyncSubject received: Second value
이렇게 Subject에 대해 간략하게 공부를 해보았습니다!!. 언제나 피드백은 환영입니다! 감사합니다!
'iOS > RxSwift' 카테고리의 다른 글
| [RxSwift] Create / Defer (1) | 2024.12.20 |
|---|---|
| [RxSwift] Map / FlatMap (0) | 2024.12.20 |
| [RxSwift] Observable (0) | 2024.12.20 |
| [RxSwift] RxSwift를 왜 쓰는걸까? 효율적인 비동기 (0) | 2024.12.20 |
| [RxSwift] RxSwift를 왜 쓰는걸까? 데이터 바인딩 (0) | 2024.12.20 |