Subject

  • Observable은 이벤트를 전달할 수만 있고 다른 Observable을 구독할 수 없다.
  • Observer는 Observable을 구독할 수 있지만 이벤트를 전달할 수 없다.
  • Subject는 이벤트를 전달할 수 있고, 다른 Observable을 구독할 수 있다. 즉 Observable이자 Observer인 셈이다.

PublishSubject

  • 가장 기본적인 Subject로 생성 시점에는 아무런 값도 없기 때문에 구독이 시작되도 아무런 값을 방출하지 않는다.
  • PublishSubject는 구독한 시점 이후부터 발생한 값을 방출한다.
let publishSubject = PublishSubject<String>()
publishSubject.onNext("Hello") // 구독자가 없기 때문에 무시
publishSubject.subscribe { print($0) } // 구독했으나, 구독한 시점 이후부터 발생한 값이 없기 때문에 무시
publishSubject.onNext("HI") // next(HI)
  • onCompleted() 혹은 onError(_:) 이벤트를 만나게 되면 더 이상 onNext(_:) 이벤트를 통해 새로운 값을 전달할 수 없으며, 이 이벤트 이후에는 새로운 구독이 발생해도 더 이상 값을 전달할 수 없고 마지막 상태만을 전달한다.
publishSubject.onCompleted() // completed
publishSubject.onNext("RxSwift") // 이미 completed 되었기 때문에 무시
publishSubject.subscribe { print($0) } // completed (새로운 구독이지만 이미 completed 상태이기 때문)

BehaviorSubject

  • PublishSubject와는 다르게 생성 시점에 값을 가지고 있으며, 구독이 시작됐을때 가지고 있는 값을 전달한다.
  • BehaviorSubject는 새로운 구독자에게도 늘 마지막 값을 전달한다.
  • 반면 PublishSubject처럼 completed 혹은 error 상태에서는 새로운 구독이 발생해도 값을 전달할 수 없고 마지막 상태를 전달한다.
let behaviorSubject = BehaviorSubject.init(value: 0)
behaviorSubject.subscribe { print($0) } // next(0)
behaviorSubject.onNext(1) // next(1)
behaviorSubject.subscribe { print($0) } // next(1)
behaviorSubject.onCompleted() // completed * 2
behaviorSubject.onNext(11) // 무시
behaviorSubject.subscribe { print($0) } // completed

ReplaySubject

  • BehaviorSubject는 최신 이벤트를 가지고 있다가 구독자에게 전달하기 때문에 최신 이벤트를 제외한 모든 이벤트는 사라진다.
  • ReplaySubject는 이와 다르게 직접 bufferSize를 통해 최신 이벤트로부터 몇개의 이벤트를 저장할지 직접 설정할 수 있다.
  • ReplaySubject는 create(bufferSize:)를 통해 생성한다.
  • 새로운 구독자가 생기면 지정된 bufferSize만큼 저장된 이벤트를 전달하지만, 이미 구독중인 구독자에게는 최신 이벤트만 전달한다.
  • bufferSize는 메모리를 사용하기 때문에 bufferSize에 신경써야 한다.
  • completed 혹은 error 상태인경우 새로운 구독이 발생하면 저장된 이벤트를 전달하고 마지막으로 상태를 전달한다.
let replaySubject = ReplaySubject<Int>.create(bufferSize: 3)
replaySubject.subscribe { print($0) } // 아무런 이벤트도 없기 때문에 무시
replaySubject.onNext(1) // next(1)
replaySubject.onNext(2) // next(2)
replaySubject.onNext(3) // next(3)
replaySubject.onNext(4) // next(4)

replaySubject.subscribe { print("new subscribe \($0)") } // new subscribe next(2) -> new subscribe next(3) -> new subscribe next(4)

replaySubject.onCompleted() // completed, new subscribe completed
replaySubject.subscribe { print("last subscribe \($0)") } // last subscribe next(2) -> last subscribe next(3) -> last subscribe next(4) -> last subscribe completed

AsyncSubject

  • AsnycSubject는 completed 상태인 경우에만 마지막 이벤트를 구독자에게 전달한다.
  • completed 상태가 되면 마지막 이벤트와 함께 completed 상태를 전달하며, error인 경우에는 completed와는 다르게 아무런 이벤트를 전달하지 않고 error만을 전달한다.
let asyncSubject = AsyncSubject<Int>()
asyncSubject.subscribe { print($0) }
asyncSubject.onNext(1) // 무시
asyncSubject.onNext(2) // 무시
asyncSubject.onCompleted() // next(2) -> completed

enum MyError: Error {
    case error
}

let asyncSubject2 = AsyncSubject<Int>()
asyncSubject2.subscribe { print("error case \($0)") }
asyncSubject2.onNext(10) // 무시
asyncSubject2.onNext(11) // 무시
asyncSubject2.onError(MyError.error) // error case error(error)

Relay

  • PublishRelay는 PublishSubject를 Wrapping하고 있고 BehaviorRelay는 BehaviorSubject를 Wrapping하고 있다.
  • Relay는 이벤트를 받아 구독자에게 전달하지만, 오로지 next 이벤트만 전달할 수 있다.
  • completed나 error는 전달받지도, 하지도 않기 때문에 구독자가 disposed되기전까지 무한정으로 살아있다.
  • 이런 특징 때문에 주로 UI에 사용된다.
  • Relay는 Subject와 다르게 onNext(_:)가 아닌 accept(_:)를 통해 새로운 이벤트를 전달한다.
  • BehaviorSubject는 value 속성에서 값을 읽을 수 있다. (읽기전용)
let publishRelay = PublishRelay<Int>()
publishRelay.subscribe { print($0) }
publishRelay.accept(5) // next(5)

let behaviorRelay = BehaviorRelay(value: 55)
behaviorRelay.accept(66)
behaviorRelay.subscribe { print($0) } // next(66)
behaviorRelay.accept(33) // next(33)
print(behaviorRelay.value) // 33 (읽기전용)