티스토리 뷰

Mobile/iOS

RxSwift. Observable과 Driver

out of coding 2018. 3. 3. 09:35

오늘은 RxSwift에 대해서 이야기를 해볼까 합니다.


저는 이걸 이용해서 MVVM 패턴의 프로그램을 기반으로 프로젝트를 진행하고 있습니다.


Reactive 프로그램은 정말 별다른건 아니고 상태 상태에 따른 값의 변화에 따른 filter, map 조작등을 통한 UI의 컴퍼넌트들과 bind하여주는 용도로 이용하고 있습니다.


ViewModel에는 당연히 로직이 들어가고 ViewController는 bind하여주기 위한 역할이죠...


일단 Rx에 대해서 이해도가 조금 낮은 분들은 이해하는 정도로만 봐주시기 바랍니다.


저도 처음에는 외계어를 듣는거 같았거든요. ㅎㅎ


들어가기전에 제가 사용하는 RxSwift 버전은 4.0입니다. 3.0을 사용하시는분들과는 거어어어어의 비슷한데 약간 다른 예약어가 있으니 이점은 참고하시기 바랍니다.


1. Driver


RxSwift를 사용하게 되면 다른것들과 다르게 Driver라는것을 이용할 수 있습니다.

조금 다른점은 RxCocoa를 import 하여 주어야 합니다.


import RxCocoa

import RxSwift


저는 거의 이런식입니다. 개발할때...

자 그럼 다른곳에서도 사용하는 Observable이 있는데, 왜 궂이 Driver가 존재하는것이 궁금하실겁니다.

이유는 Observable은 생성된 Thread의 영향을 받습니다.

왜냐면 모든 작업들은 BackgroundScheduler에서 작업을 하고 UI 변경점만 MainScheduler에서 처리를 하여 주어야 하는데요.


Driver는 MainScheduler에서 동작을 합니다.

Driver의 내부입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var driverObserveOnScheduler: SchedulerType = MainScheduler.instance
public func asDriver(onErrorDriveWith onErrorDriveWith: Driver<E>-> Driver<E> {
    let source = self
        .asObservable()
        .observeOn(driverObserveOnScheduler)
        .catchError { _ in
            onErrorDriveWith.asObservable()
        }
    return Driver(source)
}
public struct Driver<Element> : DriverConvertibleType {
    public typealias E = Element
    let _source: Observable<E>
    init(_ source: Observable<E>) {
        self._source = source.shareReplayLatestWhileConnected()
    }
}
cs


Driver의 init을 보게 되면 shareReplayLastestWhileConnected가 보일겁니다.

이것의 의미는 하나의 next가 들어오게 되면 그 동작은 마무리가 되게 되는데, 이것을 사용하게 되면 구독하고 있는 모든 객체에 값을 전달하게 됩니다.


2. 어떤때 사용해야 하는가?


1
2
3
4
5
6
7
8
9
let idEvent = idTextField.rx.text.orEmpty.asDriver()
let passEvent = passTextField.rx.text.orEmpty.asDriver()
        
let buttonEnableEvent = Driver.combineLatest(idEvent, passEvent)
    .map { !$0.0.isEmpty && !$0.1.isEmpty }
        
buttonEnableEvent
    .drive(button.rx.isEnabled)
    .disposed(by: disposeBag)
cs


이 예제는 id와 password textfield를 하나씩 두고 그것의 입력에 따라서 UI가 동적으로 변경되도록 만든 코드입니다.


설명을 드리면, id, pass가 5번째 라인처럼 isEmpty가 아닐 경우에는 drive에 전달된 값에 따라서 enable이 변경이 되게 되는겁니다.


그럼 Observable로 만들어 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
let idEvent = idTextField.rx.text.orEmpty.asObservable()
    .observeOn(MainScheduler.instance)
    .share(replay: 1, scope: .whileConnected)
let passEvent = passTextField.rx.text.orEmpty.asObservable()
    .observeOn(MainScheduler.instance)
    .share(replay: 1, scope: .whileConnected)
 
let buttonEnableEvent = Observable.combineLatest(idEvent, passEvent)
    .map { !$0.0.isEmpty && !$0.1.isEmpty }
 
buttonEnableEvent
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { button.isEnabled = $0 })
    .disposed(by: disposeBag)
cs


무언가 줄이 길어졌습니다.


왜냐면 Driver는 내부에서 이 작업을 해주고 있기 때문이죠.


언제 사용하느냐? 그건 UI에 직접적으로 접근할 경우에는 Driver를 사용하는것이 더 맞을것 같고요. 그렇지 않고 로직만 처리를 하는 부분이라면 Observable을 이용하여서 Background에서 작업을 하는것이 맞다라는겁니다.


솔찍히 이런거 생각안하고 그냥 대충 짜도 됩니다만... 대신 어플 성능이 안 좋겠죠 ^^

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함