[RxSwift #5] Driver란 무엇일까?

2022. 1. 1. 19:03ReactiveX

일단 정말정말 오랜만에 글을 쓴다. 작년 추석 때가 마지막이었던 것 같은데.... 중간고사 기간부터 종강할 때까지 너무너무 바빴다..! 그래서 사실 Driver에 관한 글을 써야한다는 사실도 잊고있었다.

일단 마지막으로 글을 쓴게 작년이라니!! 오늘은 벌써 새해가 되었다. 신년이다. 어떻게 이럴수가!!! 

 

 

간단하게 복습

일단 지난 글에서 다뤘던 것을 간단하게 복습하자면, Relay에 관한 내용을 공부했었다. Relay는 Subject를 Wrapper class로 감싼 형태로, error나 complete를 발생하지 못하게 하는 것이 목적이었다. 그렇다면 이제 이 Relay의 사용법을 알아야 한다. 왜 Wrapper 클래스로 감쌌으며, 어떤 목적을 위해, 어떻게 사용해야 할까?

 

 

Driver란?

먼저 Driver라는 것을 알아보자. Driver는 relay와 마찬가지로 RxCocoa를 import해야 사용 가능하다. 다른 rx구현체에는 없지만, rxswift에서만 구현되어 있는 개념이다. 이는 저번 글에서 공부했던 relay를 관찰할 때 사용할 수 있다.

 

Relay는 observer과 observable이 동시에 될 수 있는 Subject의 wrapper class였다. Relay를 관찰할 때는 observable 대신 이것의 wrapper class인 Driver의 형태로 바꾸어서 관찰을 하게 할 수 있다. 

 

Driver는 Main Thread에서 작업하고 싶을 때 Observable 대신 사용하게 된다. 즉 UI 작업에 적합하다. Observable은 기본적으로 main thread에서 동작하지 않고 background thread에서 동작하며, 어느 scheduler에서 동작 할지 직접 설정해줄 수도 있다. driver로 변환하고 싶을 때는 다음과 같이 asDriver()를 호출하면 된다.

let relay = BehaviorRelay<Int>(value: 0)

let driver = relay.asDriver()

관찰을 할 때 PublishRelay는 초기값이 없을 수 있으므로, BehaviorRelay에서 Driver를 사용하여 관찰할 수 있다.

 

그렇다면 asDriver()가 어떻게 구현되어 있는지 보도록 하자. 저번 글에서 봤던 Relay의 코드를 다시 살펴보자.

public final class BehaviorRelay<Element>: ObservableType {
    private let _subject: BehaviorSubject<Element>

    /// Accepts `event` and emits it to subscribers
    public func accept(_ event: Element) {
        self._subject.onNext(event)
    }

    /// Current value of behavior subject
    public var value: Element {
        // this try! is ok because subject can't error out or be disposed
        return try! self._subject.value()
    }

    /// Initializes behavior relay with initial value.
    public init(value: Element) {
        self._subject = BehaviorSubject(value: value)
    }

    /// Subscribes observer
    public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
        return self._subject.subscribe(observer)
    }

    /// - returns: Canonical interface for push style sequence
    public func asObservable() -> Observable<Element> {
        return self._subject.asObservable()
    }
}

 

여기는 relay를 driver로 바꿔주는 함수가 없다. 이는 extension에 구현되어 있었다.

 

extension BehaviorRelay {
    /// Converts `BehaviorRelay` to `Driver`.
    ///
    /// - returns: Observable sequence.
    public func asDriver() -> Driver<Element> {
        let source = self.asObservable()
            .observeOn(DriverSharingStrategy.scheduler)
        return SharedSequence(source)
    }
}

 

여기에 나와 있는 DriverSharingStrategy를 따라 들어가보면 main scheduler로 설정하고 있는 것을 볼 수 있다. 타고 들어가보면 다음과 같은 문장을 발견할 수 있다.

public private(set) static var make: () -> SchedulerType = { MainScheduler() }

 

이렇게 Driver를 생성하면 된다. asDriver()의 리턴 타입을 보면 Driver임을 알 수 있다.

 

생성된 Driver를 구독하기 위해서는 drive(onNext: )를 사용하면 된다. 이는 Observable에서의 subscribe와 비슷한 역할을 한다.

driver.drive(onNext: { res in
            print(res)
        })
        .disposed(by: disposeBag)

 

 

Relay에서의 subscribe

위에 BehaviorRelay에 관한 코드를 보면 subscribe() 함수가 따로 있는 것을 볼 수 있다. 이제까지는 Driver로 변환해서 drive하는 방식을 살펴봤는데, subscribe()를 하는 방식은 driver로 변환하지 않고 observable을 구독하는 방식이 될 것이다. 이는 main thread에서 작업하지 않을 때 사용할 수 있는 방법이다.

 

 

 

Driver는 UI 작업을 위해 사용되는데, 이렇게 UI 처리에 특화된 옵저버블을 Traits라고 한다. 다음 글에서는 Driver외에도 여러 Traits에 관해 공부해보려고 한다.

'ReactiveX' 카테고리의 다른 글

[RxSwift #6] Traits(1) - RxSwift Traits  (0) 2022.01.07
[RxSwift #4] Subject 와 Relay  (2) 2021.09.22
[RxSwift #3] Scheduler  (0) 2021.09.20
[RxSwift #2] Observable에 대해  (0) 2021.09.19
[RxSwift #1] 자주 쓰이는 용어와 개념  (0) 2021.09.17