[RxSwift] RxCocoa의 Traits - Signal, Driver, Relay

728x90

RxCocoa는 UIKit의 Rx extension 이다.

UI특징

  • 항상 UI 스레드에서만 처리해야한다.
  • 화면을 그리다 에러가 나면 스트림이 끊어져도 에러를 처리하고 다시 돌아야함.

RxCocoa의 Traits는 위 조건을 지키면서 UI를 처리할 수 있다.

RxCocoa의 Traits를 알아보자!

RxRelay

Subject와 같지만 에러가 나도 끊어지지 않고 무시. onNext 이벤트만 존재하고, dispose를 통해 종료할 수 있다.

실시간으로 UI를 변경해야할 때 Subject 대신에 Relay를 쓴다.

Relay에는 PublishRelay와 BehaviorRelay가 있다. 특성은 PublishSubject, BehaviorSubject 와 동일하다.

PublishRelay는 초기값이 없고 구독한 이후 발생한 이벤트만 방출한다.

BehaviorRelay는 초기값을 설정할 수 있고 구독시 최근 이벤트 없다면 초기값을 방출하고 이후 이벤트들을 방출한다.

 

/*-PublishRelay-*/
let a = PublishRelay<Int>()
a.accept(1)
a.subscribe { value in
    print(value)
}.disposed(by: disposeBag)
a.accept(2)
a.accept(3)

/*-BehaviorRelay-*/
let b = BehaviorRelay<Int>(value: 100)
//b.accept(101)
b.subscribe { value in
    print(value)
}.disposed(by: disposeBag)
b.accept(200)
b.accept(300)
/* a 출력 결과
2
3
*/

/* a 출력 결과
100
200
300
*/
// 주석 풀면 101, 200, 300

 

Driver, Signal

공통점

  • 절대 종료되지 않는다. (에러를 방출하지 않는다.)
  • MainScheduler에서 동작하는것이 보장된다. 하지만 observeOn()을 통해 스케줄러를 변경할 수 있지만 권장하지 않는다.

차이점

  • Signal은 구독 이후의 이벤트를 방출하고 Driver은 구독을 하면 가장 최근의 이벤트를 방출한다.
  • Driver의 경우 가장 최근의 이벤트를 받기 때문에 이 이벤트가 다른 스케줄러에서 실행하는 경우가 있기 때문에 주의해야 한다.
  • RxCocoa Trait 중 Signal만 자원을 공유하지 않는다

Driver는 BehaviorRelay와 많은 공통점을 가지고 있고 실제로 같이 쓰는 경우가 많습니다.

Signal은 PublishRelay와 많은 공통점을 가지고 있고 실제로 같이 쓰는 경우가 많습니다.

let results = query.rx.text.asDriver()        // Driver로 캐스팅
    .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
            .asDriver(onErrorJustReturn: [])  // 에러 발생시 리턴값 설정
    }

results
    .map { "\($0.count)" }
    .drive(resultCount.rx.text)               // If there is a `drive` method available instead of `bind(to:)`,
    .disposed(by: disposeBag)              // that means that the compiler has proven that all properties
                                              // are satisfied.
results
    .drive(resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
        cell.textLabel?.text = "\(result)"
    }
    .disposed(by: disposeBag)

Observable을 asDriver 연산자를 사용해 Driver 로 변환하고 Subscribe 대신에 drive를 통해 이벤트를 방출한다.

Signal은 asSignal을 통해 Signal로 변환하고 emit()을 통해 구독을 한다.

728x90