이 포스팅은 RxSwift 시리즈 3 편 중 2 번째 글 입니다.

  • Part 1 - 01: Concept
  • Part 2 - This Post
  • Part 3 - 03: 프로젝트 적용하기
▼ 목록 보기

복습

  • 왜 사용?
    • 비동기적으로 처리하는 데이터를 타입으로 리턴하기 위한 방법
    • 비동기적으로 생기는 데이터를 나중에생기는데이터 클래스 타입으로 감싸서 마치 데이터가 있는 것 마냥 타입으로 받는 것처럼 착각을 주게하는 방법
    • 실제 받아서 사용할 때 해당 동작이 발생한다.

Sugar API

  • 근데 앞의 코드를 보면 너무 사용법이 길다.
  • 귀찮은 것을 없애주는 API를 알아보자.

그냥 하나의 데이터를 보내는 방법 (Just)

private func downloadJson(url: String) -> Observable<String?> {
        
    Observable.create { emitter in
        emitter.onNext("Hello")
        emitter.onCompleted()
        
        return Disposables.create()
    }
}
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.just("hello")
}
  • 이렇게 간단하게 보낼 수 있다.

요소를 하나씩 보내고 싶으면? (from)

  • 만약에 두개를 보내고 싶으면?
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.just(["hello", "world"])
}
  • 이렇게 보내면 근데 배열 자체가 넘어가게 됨
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.from(["hello", "world"])
}
  • 이렇게 하면 요소 하나씩 onNext로 넘어간다.

onNext만 받고 싶은 경우 (subscribe(onNext:))

_ = downloadJson(url: MEMBER_LIST_URL)
    .subscribe { [weak self] event in
        switch event {
        case .next(let json):
            DispatchQueue.main.async { [weak self] in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            }
        case .error(let error):
            print(error)
        case .completed:
            break
        }
    }
  • 이렇게 계속 쓰는 것은 너무 불편하다.
  • completed 된 경우나 error인 경우 할 동작이 없다면 이렇게 써도 된다.
_ = downloadJson(url: MEMBER_LIST_URL)
    .subscribe(onNext: {
        DispatchQueue.main.async { [weak self] in
            self?.editView.text = json
            self?.setVisibleWithAnimation(self?.activityIndicator, false)
        }
    })
  • 이렇게만 사용하는 방법도 있다.
  • onComplted, onDisposed 등등이 있다.

처리하는 스레드를 변경하는 방법 (.observeOn)

@IBAction func onLoad() {
    self.editView.text = ""
    self.setVisibleWithAnimation(self.activityIndicator, true)
    
    _ = downloadJson(url: MEMBER_LIST_URL)
        .subscribe(onNext: { json in
            DispatchQueue.main.async { [weak self] in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            }
        })
    
}
    
  • 기존에는 UIupdate를 하기 때문에, URLSession을 수행하고 있는 스레드에서 main 스레드에서 업데이트를 진행하도록 dispatchQuee를 사용했다.
@IBAction func onLoad() {
    self.editView.text = ""
    self.setVisibleWithAnimation(self.activityIndicator, true)
    
    _ = downloadJson(url: MEMBER_LIST_URL)
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { [weak self] json in
            self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
        })
    
}
    
  • 이렇게 수행하는 동작의 스레드를 변경하여 작업할 수 있다.
  • 이렇게 subscribe 데이터 처리 전에 다른 동작을 수행해주는 녀석들을 Operator 라고 한다.
    • map, filter 등도 해당된다.

Dispose 한번에 하기 (DisposeBag)

  • 처리해야 하는 작업들의 dispose를 배열로 들고 있다가 viewWillDisappear시에 모두 dispose 하는 방법도 있다.
  • 하지만 sugar api가 존재하는데,
var disposeBag = DisposeBag()

func temp() {
    _ = downloadJson(url: MEMBER_LIST_URL)
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] json in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            })

    self.disposeBag.insert(disp)
}
  • 이렇게 해두면, 해당 VC안에 사용하는 변수로서 등록되기 때문에, VC가 Disappear되는 시점에 자동으로 bag안에 담긴 모든 disposable이 dispose된다.
  • 이것도 싫다!
func temp() {
    _ = downloadJson(url: MEMBER_LIST_URL)
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] json in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            })
            .disposed(by: self.disposableBag)
}
  • 이렇게 간결하게 처리할 수도 있다.

Marble Diagram 읽기

  • Sugar API는 무지하게 많다.
  • 함수의 종류가 엄청나게 많은 것처럼 엄청 많다.
  • 이걸 외워서 사용할 수 없으니, 동작을 찾아서 적용해야 하는데, 이 때 설명하는 방식이 Marble Diagram이다.
  • ObserveOn 함수의 예시를 보자.

imageobserveOn

  • 먼저 파란색 줄 위에 올라와 있는 데이터들은 Observable이다.
  • 특정 연산자들은, raw Data를 Observable로 바꿔주는 역할을 수행하는데 (from) 이경우는 화살표위에 올라와 있지 않다.
  • 아래의 박스는 Operator를 의미한다.
  • 처음을 보면 일반적으로 시작하는 검은색 화살표가 아닌 파란색 화살표로 시작한다.
  • 이 이유는 아래에 보면 보이는 SubscribOn 함수의 영향이다.
  • ObserveOn 함수를 시작하면 Observable 객체들이 해당 operator가 지정하는 스레드에서 동작을 수행하게 되는데, 영어를 해석해보면, 이러한 스레드에서 관찰을 해줘 라는 의미이다.
  • 즉, 관찰하는 쪽(예를 들어 View) 에서 사용할 스레드를 변경할 때 사용한다.
  • SubscribOn의 경우 어느 스레드에서 구독 작업을 시작할 것인지를 결정한다.
  • 그래서 어느 시점에 해당 함수가 있는지에 상관없이 처음 작업을 실행하는 스레드가 파란색이 된 것을 볼 수 있다.

Reference