개발콩블로그

[RxSwift] PublishSubject, BehaviorSubject, ReplaySubject, AsyncSubject 본문

RxSwift

[RxSwift] PublishSubject, BehaviorSubject, ReplaySubject, AsyncSubject

devBean 2025. 2. 26. 23:56

안녕하세요 개발콩입니다!

RxSwift는 사용하는 것도 중요하지만 잘 알고 적절하게 사용하는 것이 중요한 것 같습니다.

오늘은 Subject에 대해서 알아보도록 하겠습니다.

 

 

Subject

  • 이벤트 방출하는 Observable의 역할을 수행할 수 있습니다.
  • 이벤트를 받고 처리하는 Observer의 역할을 수행할 수 있습니다.

Subject의 종류에는 4가지가 있습니다.

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject

4가지의 Subject에 대해서 알아보도록 하겠습니다.

 

 

PublishSubject

  • 초기값이 없습니다.
  • 구독 이후의 시점부터 방출되는 이벤트를 처리할 수 있습니다.
let publishSubject = PublishSubject<String>()

publishSubject
    .subscribe { eventString in
        print("onNext - \(eventString)")
    } onError: { error in
        print("onError - \(error)")
    } onCompleted: {
        print("onComplete")
    } onDisposed: {
        print("onDisposed")
    }
    .disposed(by: disposeBag)

이벤트가 방출되었을 때 처리하는 이벤트를 정의했습니다.

 

 

아래의 이벤트를 보내보도록 하겠습니다.

publishSubject.onNext("안녕하세요") // onNext - 안녕하세요
publishSubject.onCompleted() // onComplete, onDisposed

publishSubject.onNext("반가워요") // 출력 X

구독시점 이후에 onNext method를 사용해서 이벤트를 방출할 수 있습니다.

여기서 중요한 것은 complete된 이후에 onDisposed가 동작하고 그 이후에는 값을 방출하지 않습니다.

 

 

publishSubject.onNext("안녕하세요") // onNext - 안녕하세요
publishSubject.onError(SampleError.error) // onError - error, onDisposed

publishSubject.onNext("반가워요") // 출력 X

이것은 Error가 방출되고 나서 onDisposed가 동작하고 그 이후에는 값을 방출하지 않고 stream이 끊어진 것을 확인할 수 있었습니다.

다른 Observable의 생명주기도 위와 같습니다.

 

 

 

BehaviorSubject

  • 초기값이 존재합니다.
  • 구독 시점에 가장 최근에 방출된 이벤트를 처리합니다.
  • 최근에 방출된 이벤트가 없다면 초기값을 처리할 수 있습니다. (초기값이 필요한 이유입니다)
let behaviorSubject = BehaviorSubject(value: "첫 인사말로 반가워요!")

behaviorSubject
    .subscribe { eventString in
        print("onNext - \(eventString)")
    } onError: { error in
        print("onError - \(error)")
    } onCompleted: {
        print("onComplete")
    } onDisposed: {
        print("onDisposed")
    }
    .disposed(by: disposeBag)

// onNext - 첫 인사말로 반가워요!
behaviorSubject.onNext("안녕하세요") // onNext - 안녕하세요

 

구독과 동시에 "첫 인사말로 반가워요!"초기값을 처리하는 것을 볼 수 있습니다.

이후의 동작은 PublishSubject와 동일합니다.

 

let behaviorSubject = BehaviorSubject(value: "첫 인사말로 반가워요!")

behaviorSubject.onNext("구독 전의 인사말 !")

behaviorSubject
    .subscribe { eventString in
        print("onNext - \(eventString)")
    } onError: { error in
        print("onError - \(error)")
    } onCompleted: {
        print("onComplete")
    } onDisposed: {
        print("onDisposed")
    }
    .disposed(by: disposeBag)

// onNext - 구독 전의 인사말 !
behaviorSubject.onNext("안녕하세요") // onNext - 안녕하세요

구독 시점 이전에 방출된 값이 있다면 해당 event를 처리하는 것을 확인할 수 있습니다.

 

 

 

 

ReplaySubject

  • 초기값이 없습니다.
  • 선언된 bufferSize만큼 이벤트를 갖고있다가 구독 시점에 이벤트를 전달합니다.
  • Error가 발생하더라도 바로 stream이 끊어지지 않고 갖고있는 이벤트를 방출한 이후 stream이 해제됩니다.
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)

replaySubject.onNext("안녕하세요")
replaySubject.onNext("반갑습니다.")
replaySubject.onNext("개발콩입니다!")
replaySubject.onError(SampleError.error)

replaySubject
    .subscribe { eventString in
        print("onNext - \(eventString)")
    } onError: { error in
        print("onError - \(error)")
    } onCompleted: {
        print("onComplete")
    } onDisposed: {
        print("onDisposed")
    }
    .disposed(by: disposeBag)

// onNext - 반갑습니다.
// onNext - 개발콩입니다!
// onError - error
// onDisposed

 

 

 

AsyncSubject

  • 초기값이 없습니다.
  • 구독시점 이후 onNext로 이벤트가 방출되어도 처리하지 않습니다.
  • completed 이벤트가 전달된 이후 가장 최근에 전달된 값을 방출합니다.
let asyncSubject = AsyncSubject<String>()

asyncSubject.onNext("안녕하세요")
asyncSubject.onNext("반갑습니다.")
asyncSubject.onNext("개발콩입니다!")
asyncSubject.onCompleted()

asyncSubject
    .subscribe { eventString in
        print("onNext - \(eventString)")
    } onError: { error in
        print("onError - \(error)")
    } onCompleted: {
        print("onComplete")
    } onDisposed: {
        print("onDisposed")
    }
    .disposed(by: disposeBag)
    
// onNext - 개발콩입니다!
// onComplete
// onDisposed

 

 

4개의 Subject의 차이점에 대해서 알아보았습니다.

이 글을 읽고 4개의 Subject에 대해서 차이점을 명확히 알고 적절한 상황에 사용할 수 있으면 좋겠습니다.