ref : https://joycestudios.tistory.com/88
- 공통점
Observable 의 역할과 Observer 의 역할을 모두 할 수 있다.
- 차이점
- Relay 는 RxCocoa 의 클래스, Subject 는 RxSwift 내의 클래스다.
- Subject 는 .completed, .error 등의 이벤트가 발생하면 subscribe 가 종료된다. Relay 객체는 .completed, .error 등을 발생시키지 않고 Dispose 되기 전까지 계속 동작하기 때문에 UI 작업에서 사용하기 용이하다. RxCocoa 에 포함 되어있다는것 자체도 UI 작업을 위한 클래스라는 것을 의미하기도한다.
- Subject 에서의 값 입력 : mySubject.onNext( x )
값 출력 : mySubject.subscribe { value in ... }
Relay 에서의 값 입력 : myRelay.accept( x )
값 출력 : myRelay.value
PublishSubject, BehaviorSubject, ReplaySubject 등이 있지만 난 현재 Publish 와 Behavior 를 가장 자주 쓰고있다. 그래서 이 둘을 비교해서 기록한다. 그리고 PublishSubject 의 개념은 PublishRelay 에도 적용해서 이해할 수 있다.
쉬운 결론부터 내리자면, 둘의 차이점은 초기값이 있냐 없냐로 구분 지을 수 있다.
Publish
- 초기값이 없다.
- 구독을 한 뒤로 발행하는 모든 값들에 반응한다.
Behavior
- 초기값이 있다. x 라는 초기값을 가지고, 값을 발행받기 전이라면 x 라는 값으로 대체해서 사용한다. 그 뒤로 구독을 하는 구독자는 가장 최근의 값을 초기값으로 가진다.
- 구독을 한 뒤로 발행하는 모든 값에 반응한다.
ViewController 의 UILabel 에 서버에서 가져온 텍스트를 띄워줘야 하는 상황이라고 할 때, 각각 다음과 같은 코드를 작성할 수 있다.
BehaviorSubject 를 사용한 코드
- ViewModel.swift
let textSubject = BehaviorSubject<String>(value: "...") // RxMoya moyaProvider.rx.request(.getLabelText()) .map(entity.self) .subscribe(onSuccess: {[weak self] result in self?.textSubject.onNext(result) }, onFailure: { [weak self] error in print(error) }).disposed(by: bag)
- ViewController.swift
var myLabel = UILabel() // viewModel binding viewModel.textSubject.subscribe(on: MainScheduler.instance) .bind { [weak self] text in self.myLabel.text = text }.disposed(by: bag) // 현재 뷰모델이 가진 텍스트를 출력하고 싶은 경우 -> 다시 구독을 해줘야 함 viewModel.textSubject.bind { [weak self] text in print(text) }.disposed(by: bag)
BehaviorRelay 를 사용한 코드
- ViewModel.swift
let textRelay = BehaviorRelay<String>(value: "...") // RxMoya moyaProvider.rx.request(.getLabelText()) .map(entity.self) .subscribe(onSuccess: {[weak self] result in self?.textRelay.accept(result) }, onFailure: {[[weak self] error in print(error) }).disposed(by: bag)
- ViewController.swift
var myLabel = UILabel() // viewModel binding viewModel.textRelay.subscribe(on: MainScheduler.instance) .bind { [weak self] text in self.myLabel.text = text }.disposed(by: bag) // 현재 뷰모델이 가진 텍스트를 출력하고 싶은 경우 -> 구독 과정을 거치지 않아도 됨 print(viewModel.textRelay.value)