RxSwift

6. RxSwift Relay, Signal, Driver

Daesiker 2021. 10. 7. 17:57
반응형

1. Relay

Relay는 RxSwift 프레임워크가 아닌 RxCocoa에서 다루는 타입이다.

Relay는 Subject와 비슷하지만 한가지 크게 다른 점이 있다.

onComplete()와 onError 이벤트가 없는 것이다.

오직 onNext()이벤트만 존재하며 구독자가 Dispose 되기 전까지 종료되지 않는다.

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

Subject와 다른 점

  • onNext() 대신에 accept()을 사용하여 이벤트를 생성한다.
  • value를 통해 마지막으로 전달된 이벤트를 확인할 수 있다.
import RxCocoa

let bag = DisposeBag()

let publishRelay = PublishRelay<Int>()


publishRelay.accept(2)

publishRelay.subscribe {
    print("1 : ", $0)
}
.disposed(by: bag)


publishRelay.accept(3)

let behaviorRelay = BehaviorRelay<Int>(value: 4)

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

behaviorRelay.accept(5)

print(behaviorRelay.value)

//1 :  next(3)
//2 :  next(4)
//2 :  next(5)
//5

Relay도 Subject와 동일하게 PublishRelay와 BehaviorRelay가 있다.

PublishRelay는 기본값이 없으며 Subscribe를 한 이후의 이벤트부터 방출을 시작한다.

accept()를 통해 2라는 이벤트를 생성하고 subscribe를 한 다음에 3이라는 이벤트를 생성하였는데

구독전에 생성한 2는 방출하지 않고 3만 방출한 것을 알 수 있다.

BehaviorRelay는 기본값이 존재하며 Subscribe를 하면 가장 최근의 받은 이벤트를 방출하고 다음 이벤트를 방출을 한다.

코드를 보면 4라는 기본값을 가진 BehaviorRelay를 선언하고 Subscribe를 한 뒤 5라는 이벤트를 생성하였는데 가장 최근 이벤트인 4를 방출하고 5를 방출한 것을 알 수 있다.

그리고 value를 통해 가장 마지막 이벤트를 가져올 수 있는 것을 알 수 있다.


2. Driver & Signal

Driver도 Relay처럼 RxCocoa 프레임워크에서 다루는 타입이다.

Relay랑 비슷한 용도이며 UI 처리를 할 때 사용하는 타입인데 차이점이 있다.

Relay와 차이점

  • 강제로 쓰레드를 변환하지 않는다면 무조건 MainThread에서 동작이 되게 보장한다.
  • onComplete()와 onNext()이벤트만 처리하고 onError()를 반환하지 않는다.

Driver과 Signal의 공통점

  • 절대 종료되지 않는다.
  • 무조건 MainScheduler에서 돌아가도록 보장이된다. 하지만 observeOn()을 통해 스케줄러를 변경할 수 있지만 권장하지 않는다.
  • 구독 역시 MainScheduler에서 하는 것이 권장되지만 Driver의 경우 가장 최근의 이벤트를 받기 때문에 이 이벤트가 다른 스케줄러에서 실행하는 경우가 있기 때문에 주의해야 한다.

Driver과 Signal의 차이점

PublishRelay와 BehaviorRelay과 마찬가지로 Signal은 구독 이후의 이벤트를 방출하고 Driver은 구독을 하면 가장 최근의 이벤트를 방출한다.

Example

let result = inputField.rx.text.asDriver() //asDriver()를 통해 Driver로 변환
	           .flatMapLatest {
	                validateText($0)
	                    .asDriver(onErrorJustReturn: false)
	            }
        
result
    .map { $0 ? "Ok" : "Error" }
    .drive(resultLabel.rx.text) //subscribe대신 drive로 구독
    .disposed(by: bag)
        
result
    .map { $0 ? UIColor.blue : UIColor.red }
    .drive(resultLabel.rx.backgroundColor)
    .disposed(by: self.bag)
        
result
    .drive(sendButton.rx.isEnabled)
    .disposed(by: bag)

//문자열을 받아서 Observable<Bool>타입으로 반환하는 함수
func validateText(_ value: String?) -> Observable<Bool> {
    return Observable<Bool>.create { observer in
        print("== \(value ?? "") Sequence Start ==")
        
        defer {
            print("== \(value ?? "") Sequence End ==")
        }
        
        guard let str = value, let _ = Double(str) else {
            observer.onError(ValidationError.notANumber)
            return Disposables.create()
        }
        
        observer.onNext(true)
        observer.onCompleted()
        
        return Disposables.create()
    }
}

이것은 UITextField의 입력된 값에 따라 UILabel의 text와 background, Button의 활성화 상태여부 UI를 바꿔주는 함수이다.

RxCocoa는 다음 포스트부터 다룰 예정이기 때문에 세밀하게 안봐도 되고 여기서는 Observable을 Drive로 변환하는 방법인 asDriver()와 Subscribe 대신에 drive를 통해 이벤트를 방출한다는 것만 알면 된다.

Signal은 asSignal()을 통해 Signal타입으로 변환이 가능하고 emit()을 통해 구독을 한다.

반응형

'RxSwift' 카테고리의 다른 글

5. RxSwift Subject  (0) 2021.10.03
4. RxSwift Operator(2)  (0) 2021.09.30
3. RxSwift Oporator(1)  (0) 2021.09.07
2. RxSwift Observable이란?  (0) 2021.09.02
1. RxSwift란?  (0) 2021.08.23