Subject와 Relay

Subject

발행할 것이 미리 정해진 Observable과는 다르게 일단 구독을 하고 추후에 발행을 하는 객체가 Subject입니다.

Observable과의 차이

ObservableSubject
누군가가 구독을 해야 발행구독을 하지 않아도 개발자가 원하는 때에 발행 가능
각 구독자에게 따로 발행모든 구독자에게 동시에 발행

Subject의 종류

Publish Subject

가장 기본이 되는 Subject입니다. 구독하기 전에도 발행할 수도 있지만 구독하지 않으면 이벤트를 받을 수 없습니다.

import RxSwift

//✅ 구현하기 (발행물의 타입을 제네릭으로 선언합니다.)
let subject = PublishSubject<String>()

//✅ 발행하기
    //🚫 해당 객체를 구독하기 전에 발행해서 출력되지 않습니다.
subject.onNext("구독전 발행 1")

//✅ 구독하기
    //🚫 구독 전에 발행한 것에 대해서는 받을 수 없습니다.
subject.subscribe { event in
    print(event)
}

//✅ 구독 이후에도 발행 가능!
subject.onNext("구독 후 발행 1")
subject.onNext("구독 후 발행 2")

//✅ dispose하거나 complete한 다음에는 추가 발행할 수 없다!
subject.dispose()
subject.onCompleted()

subject.onNext("dispose 후 발행 1") //🚫 발행 안됨
//🖨 출력 결과
next(구독 후 발행 1)
next(구독 후 발행 2)

Behavior Subject

초기 값을 가지는 subject입니다. 항상 마지막으로 발행된 값으로 초기 값을 갱신합니다.

import RxSwift

//✅ 초기 값을 가지고 발행합니다.
let subject = BehaviorSubject(value: "원래 초기 값")

//✅ 구독 전에 발행하면 이전 값을 지우고 발행된 값을 초기 값으로 가지고 있습니다.
subject.onNext("새로운 초기 값")

//✅ 구독하는 순간 초기값을 발행합니다.
subject.subscribe { event in
    print(event)
}

//✅ 구독자에게 발행하고 현재의 초기 값으로 가지고 있습니다.
subject.onNext("또 새로운 초기 값")
//🖨 출력 결과
next(새로운 초기 값)
next(또 새로운 초기 값)

Relay Subject

Behavior Subject와 유사하게 초기 값을 가지고 있지만 여러 개의 초기 값을 가지고 있다는 차이점이 있습니다.

import RxSwift

//✅ buffer size를 정의하여 발행합니다.
let subject = ReplaySubject<String>.create(bufferSize: 2)

//✅ 마지막 n개의 발행물을 buffer size만큼 가지고 있다가 발행합니다.
subject.onNext("발행 1")
subject.onNext("발행 2")
subject.onNext("발행 3")

//✅ 구독 하기
subject.subscribe {
    print("처음 구독: \($0)")
}
    //👉 발행된 값 중에 2개가 저장되어 있다가 발행됩니다.

//✅ 추가적으로 발행하는 것은 정상적으로 발행되고 buffer size만큼 최신의 발행물을 갱신하면서 저장해서 가지고 있습니다.
subject.onNext("발행 4")
subject.onNext("발행 5")
subject.onNext("발행 6")

//✅ 새롭게 구독하면 저장해둔 마지막 2개의 발행인 5, 6을 발행합니다.
subject.subscribe {
    print("두번째 구독: \($0)")
}
//🖨 출력 결과
처음 구독: next(발행 2) //👉 초기값 2개 발행
처음 구독: next(발행 3)

처음 구독: next(발행 4)
처음 구독: next(발행 5)
처음 구독: next(발행 6)

두번째 구독: next(발행 5) //👉 갱신된 초기값 2개 발행
두번째 구독: next(발행 6)

Relay

크게는 Subject와 유사한 개념이라고 보시면 됩니다. 하지만 결정적인 차이가 몇 가지 있습니다.

  • Relay는 Subject와 다르게 RxSwift가 아니라 RxCocoa에 정의되어 있습니다.
  • Subject는 completed 혹은 error의 이벤트가 발생하면 구독을 종료합니다. 반면에 Relay는 completed나 error 이벤트를 발생시키지 않습니다. dispose될 때까지 계속 발행할 수 있습니다. 이러한 특성 때문에 Relay는 UI에 더 사용하기 적합합니다.

종류

Publish Relay

Publish Subject와 거의 동일한 객체입니다. 구독하기 전에 발행된 값은 무시되고 구독하고 발행된 값만 출력되는 모습을 볼 수 있습니다.

import RxCocoa

//✅ 구현하기
let relay = PublishRelay<String>()

//✅ 발행하기
    //👉 Subject와는 다르게 accept라는 키워드로 발행
relay.accept("발행 1")

//✅ 구독하기
relay.subscribe {
    print($0)
}

relay.accept("발행 2")
relay.accept("발행 3")
//🖨 출력 결과
next(발행 2)
next(발행 3)

Behavior Relay

RxSwift에 있던 Variable이라는 클래스를 대체해서 사용할 수 있는 클래스입니다. (Variable은 deprecated 되었습니다.) 초기 값을 가지고 있고 구독하면 초기값을 발행합니다. 그리고 해당 초기 값이 변경될 때 마다 발행됩니다.

import RxCocoa

//✅ 초기값을 가지고 선언!
let relay = BehaviorRelay(value: "원래 초기 값")

//🚫 value를 직접 수정할 수 없습니다! 👉 readOnly
//relay.value = "새로운 초기 값"

//✅ value를 새로 세팅하기
relay.accept("새로운 초기 값")

//✅ asObservable로 구독할 수 있음
relay.asObservable()
    .subscribe {
        print($0) //👉 구독하자마자 초기값이 발행됨!
}

//✅ 구독하고 있을때 초기 값을 바꾸면 발행된다.
relay.accept("다시 또 새로운 초기 값")
//🖨 출력 결과
next(새로운 초기 값) //👉 구독하자마자 초기 값 발행
next(다시 또 새로운 초기 값) //👉 초기 값 바꾸면 새로 발행

좋은 웹페이지 즐겨찾기