[RxSwift] Subject, Relay, Driver 비교

이남준·2022년 2월 14일
1

1. Subject

Subject는 Observer인 동시에 Observable입니다.
그렇기 때문에 Observable과 달리 onNext를 통해 이벤트를 방출할 수 있습니다.

또한 Observabler과 Observer는 Unicast 방식으로 1:1로 방출-구독이 되는 반면에,
Subject는 Observer들과 Multicast로 연결되어, 모든 Observer에게 한 번에 이벤트를 방출할 수 있습니다.

예를 들어 아래처럼 0~100의 정수를 방출하는 Observable이 있을 때

let observable = Observable<Int>.create{ observer in
    observer.onNext(Int.random(in: 0 ..< 100))
    return Disposables.create()
}

아래처럼 subscribe하게 되면
새로운 구독마다 create가 실행되어, 방출되는 정수 값이 그때그때 달라지게 됩니다.

observable.subscribe(onNext: { print($0) })
observable.subscribe(onNext: { print($0) })
observable.subscribe(onNext: { print($0) })

// 10
// 23
// 48

하지만 subject같은 경우는 아래처럼 여러 Observer들이 같은 결과를 받게됩니다.

let subject = PublishSubject<Int>()
subject.onNext(Int.random(in: 0..<100))

subject.subscribe(onNext: { print($0) })
subject.subscribe(onNext: { print($0) })
subject.subscribe(onNext: { print($0) })

// 5
// 5
// 5

1-1. PublishSubject

PublishSubject는 초기값 없이 생성되어, onNext로 새로운 이벤트를 전달받을 때 Subscriber에게 이벤트를 방출합니다.
새로운 Subscriber는 구독 시점 이후의 이벤트들만 전달 받을 수 있습니다.

1-2. BehaviorSubject

BehaviorSubject는 PublishSubject와 달리 초기값을 가지고 생성되고, 생성과 동시에 초기값을 전달합니다.
또한 새로운 Subscriber들은 구독을 할 때, 구독 전 가장 최근 값을 전달 받습니다.

1-3. ReplaySubject

ReplaySubject는 buffer크기를 가집니다.
생성시 정해진 buffer크기만큼의 값을 새로운 Subscriber에게 전달합니다.

정리

// 초기값
PublishSubject 없음
BehaviorSubject 있음
ReplaySubject 없음

// 구독시점에 전달 받는 값
PublishSubject 없음
BehaviorSubject 가장 최근 값
ReplaySubject buffer 크기 만큼의 가장 최근 값들

2. Relay

- Error, Completed 이벤트가 방출되지 않는다.
- Next 이벤트만 방출된다.

Relay는 위의 2가지를 제외하고는 Subject와 정확히 똑같은 동작을 합니다.
Error, Completed 이벤트가 방출되지 않기 때문에, 구독이 종료되지 않아서 UI Event에 사용하기 적절합니다.

Relay의 3가지 형태 PublishRelay, BehaviorRelay, ReplayRelay는 각각 동일한 형태의 Subject의 Wrapper class입니다.

정리

- Error, Completed를 방출하지 않는 Subject

3. Driver

- 구독이 MainScheduler에서 동작
- Error 이벤트를 방출하지 않음
- SequenceShare

Driver는 RxCocoa에 포함된 Trait으로 위의 조건을 만족하는 Observable입니다.

기본 Observable과 다르게, Error이벤트를 방출하지 않으면서, MainScheduler에서 구독을 처리하기 때문에, UI Binding에 사용하기 적합합니다.
또 한가지 Observable과 다른 점은 구독 메소드를 subscribe()가 아닌 drive()를 사용한다는 점입니다.

public struct DriverSharingStrategy: SharingStrategyProtocol {
    public static var scheduler: SchedulerType { SharingScheduler.make() }
    public static func share<Element>(_ source: Observable<Element>) -> Observable<Element> {
        source.share(replay: 1, scope: .whileConnected)
    }
}

위처럼 Driver가 구현된 부분을 보면 source를 share하는 것을 알 수 있는데,
그렇기 때문에 Subject와 같이 새로운 구독이 create를 실행시키지 않고, 같은 Sequence를 공유하는 것을 알 수 있습니다.

정리

- Error를 방출하지 않는 Observable
- MainScheduler에서 구독이 동작
- UI Binding에 사용하기 적절
profile
iOS 개발자의 기록

0개의 댓글