새소식

📱 iOS/-- RXSwift

RxSwift (2) - Subject & Relay

  • -

Subject

이벤트 전달 방향: Observable -> Observer
Observer는 이벤트를 전달할 수 없고, Observer를 구독할 수도 없다. (Observable만 구독할 수 있다.)
이 사이에서 도움을 주는게 Subject이다.

Observable -> Subject(Observable or Observer) -> Observer
요런식으로 Subject는 Observable이나 Observer가 원래 못하던 이벤트 전달을 도와주게된다. 즉, Subject는 Observer도 될 수 있고, Observable도 될 수 있다.
두가지 역할을 모두 할 수 있다.

4가지 종류의 Subject

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject

Subject를 wrapping하고 있는 두가지 Realy를 제공한다.

  • PublishRelay (publishSubject wrapping)
  • BehaviorRelay (BehaviorSubject wrapping)

PublishSubject

전달받은 이벤트를 Observer에게 전달해주는 가장 기본형태의 Subject이다.
최초에 생성할때는 빈 형태로 생성해야한다. (내부에 element가 없는 상태로)
let subject = PulishSubject<String>()

구독 이후에 발생된 이벤트만 Observer에게 전달한다. marbleDiagram확인할것!!
Subject가 (Completed or Error)된 이후에는 onNext를 해도 이벤트가 observer에게 전달되지않는다.

Behavior Subject

let publishSubject = PublishSubject<Int>()
let behaviorSubject = BehaviorSubject<Int>(value: 3)
behaviorSubject.subscribe { event in
    print("behaviorSubject1 >> ",event)
}
behaviorSubject.onNext(283)
behaviorSubject.subscribe { event in
    print("behaviorSubject2 >> ",event)
}

publishSubject와는 다르게 behaviorSubject는 초기값을 한개 갖는다. Observer가 구독을 하게 되면 바로 이 초기값을 뱉어내는데, 초기값은 마지막으로 onNext를 통해 전달받은 Element가 된다.
즉, 위 코드에서는 초기값이 3이지만, 나중에는 283으로 초기값이 바뀌게된다.

ReplaySubject

onNext로 전달받은 Element들을 저장해놨다가, 새롭게 구독한 Observer에게 이름처럼 리플레이하면서 BufferSize만큼 차례대로 전달해준다. behaviorSubject와 마찬가지로 마지막에 들어온 Element들로 최신화된다.
다만 생성하는 코드가 약간 다르다. buffer의 사이즈를 지정해줘야하고, create메서드를 통해 생성해야한다.

또한 Completed된 이후에도 구독을하면 버퍼만큼 element를 뱉어준다.

let replaySubject = ReplaySubject<Int>.create(bufferSize: 3)
(1...10).forEach { replaySubject.onNext($0) }
replaySubject.subscribe {
    print("replaySubject >>> ", $0)
}

AsyncSubject

onNext로 들어온 이벤트들을 전달하지 않고 있다가, Completed가 되는 순간 마지막 이벤트 하나만을 전달한다.

let asyncSubject = AsyncSubject<Int>()

(1...100).forEach {
    asyncSubject.onNext($0)
}
asyncSubject.subscribe{
    print("asyncSubject >>> ", $0)
}

asyncSubject.onCompleted()

Relays

Relay는 subject와 유사한 특징을 갖는다. 내부에 subject를 wrapping하고 있기 때문이다.

  • PublishRealy는 PublishSubject를 갖고있다.
  • BehaviorRealy는 BehaviorSubject를 갖고있다.
  • ReplayRealy는 ReplaySubject를 갖고있다.

Subject와 Relay의 차이점

Relay는 Subject와는 다르게 next 이벤트만 전달한다. error completed 이벤트는 전달하지도, 전달 받지도 않는다는것이 차이점이다. 그리고 Relay는 OnNext가 아닌, Accept메서드를 사용한다. (명칭만다르고 기능은같음)
이 말인 즉슨, 한번 구독을 하게되면 종료가 되지 않는다는 말과 같다. 그래서 UI의 유저이벤트와 관련된 곳에 사용되는 경우가 많다.

PublishRealy

BehaviorRealy


let behaviorRelay = BehaviorRelay(value: 1)

behaviorRelay.accept(2)
behaviorRelay.subscribe{
    print($0)
}.disposed(by: bag)

behaviorRelay.accept(3)
print(behaviorRelay.value) // behaviorRealy는 value라는 프로퍼티도 제공한다. (마지막으로 저장된 값 방출하며 읽기전용이다)

ReplayRealy

let repRelay = ReplayRelay<Int>.create(bufferSize: 3)

(1...10).forEach {repRelay.accept($0)}

repRelay.subscribe {print($0)} // -> 8,9,10
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.