RxSwift 4번째, Disposable에 대해 알아보쟈

2020. 6. 13. 04:20iOS/RxSwift

이전의 포스팅에서 에서 'Stream'을 통해 들어온 데이터들에 대한 처리를 해주는 것이 바로 'Operator'라는 것을 알아보았습니다.

이 Operator중에 가장 많이 쓰는 Operator는

- Merge, Zip, CombineLast

이 3가지 입니다. 이 3가지에 대한 정보는 여기에 잘 정리되어 있습니다.

https://nsios.tistory.com/51?category=803408

 

[RxSwift] Combine Operator정리 - CombineLatest, Merge, Zip

Rx를 이용해서 개발하면서 Combine할때 유용한 Operator를 소개할게요 제 주관적으로 자주쓰이는것을 골라봤어요 Combine Operator는 말그대로 서로다른 스트림을 하나의 스트림으로 합쳐서 사용할 때 ��

nsios.tistory.com

저는 간단하게 Zip에 대한 예시를 들고 오겠습니다.

앞서서 json 데이터를 받아오는 Observable 을 생성시키는 과정을 쭉 진행해 보았었습니다. 또, 간편하게 Observable을 생성시킬 수 있는 just라는 Operator도 써 보았는데요

이렇게 생성한 두 데이터를 zip을 통해 합치는 예제 소스를 잠시 보겠습니다.

        let jsonObservable = downloadJson(MEMBER_LIST_URL)
        let helloObservable = Observable.just("Hello World")
        
        let d = Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { json in
                self.editView.text = json
                self.setVisibleWithAnimation(self.activityIndicator, false)
            })

이것처럼 두 Observable로 생성된 데이터를 합치는 과정을 진행할 수 있습니다.

이렇게 Observable 데이터의 생성, 데이터 변환, 데이터 처리 까지의 과정을 지켜보았습니다. 

- 데이터 생성

비동기적으로 생기는 데이터들에 대해 create 나, just, from 으로 얘는 비동기적으로 생기는 데이터야 ! 라고 말해주는 데이터 생성과정

- 데이터 변환

비동기적으로 데이터가 오니까 처리를 하기 어려운 점 그리고 데이터를 처리하기 전에 데이터에 대한 작업이 필요할 때 필요한 operator

- 데이터 처리

비동기적 데이터 생성이 완료되었을때 에 대한 처리

이렇게 3가지에 대한 플로우가 완성이 되면 Disposable이라는 타입이 생성되게 됩니다. 이 Disposable은 사실 이전까지 거의 방치해 두고 있었습니다. 데이터의 흐름은 위의 3가지 방식만 잘 정의되어 있다면, 알아서 잘 되게 됩니다.

그러나  이런 흐름 중간에 임의로 취소하고 싶은 동작이 있거나, 명확하게 취소해야 할 때 이용하는 것이 이 Disposable이라는 것입니다.

앞 서 Observable로 생성하고 처리에 대한 단계까지 정의한 Stream을 Disposable 이라고 하는데 이 흐름에 대한 제어권을 얻는 것이 이 Disposable 입니다.

class ViewController: UIViewController {
	var disposable : Disposable?
    
    ...
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.disposable?.dispose()
    }
    ...
	@IBAction func onLoad() {
        self.editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
        let jsonObservable = downloadJson(MEMBER_LIST_URL)
        let helloObservable = Observable.just("Hello World")
        
        self.disposable = Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { json in
                self.editView.text = json
                self.setVisibleWithAnimation(self.activityIndicator, false)
            })
    }
}

다음과 같이 생성 한 이 스트림을 뷰 컨트롤러의 멤버변수로 저장해 둡니다.

그리고 만약 화면이 사라지거나 할 때 이 흐름을 정지하고 싶다면 이 흐름에 대해 .dispose 함수를 호출하면 이 작업이 멈추게 되는 것이죠

또 여러개 가 있다면 배열로써 저장한 다음 배열에 대한 처리를 진행해 주면 됩니다.

class ViewController: UIViewController {
	var disposable: [Disposable]?
    
    ...
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.disposable?.forEach{ $0.dispose() }
    }
    ...
	@IBAction func onLoad() {
        self.editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
        let jsonObservable = downloadJson(MEMBER_LIST_URL)
        let helloObservable = Observable.just("Hello World")
        
        let d = Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { json in
                self.editView.text = json
                self.setVisibleWithAnimation(self.activityIndicator, false)
            })
        
        self.disposable?.append(d)
    }
}

그러나 ~ 이 Rx에서는 따로 멤버변수로 저장해둘 필요 없이 Disposable만 담아둘 수 있는 컨테이너를 제공합니다. 이 컨테이너는 DisposableBag이라는 것 입니다. 사용 방법도 배열처럼 간단히 .insert 함수로 저장할 수 있습니다. 또 멤버 변수로 존재하기 때문에 뷰 컨트롤러가 사라질 때 같이 사라지게 됩니다.

또 따로 변수를 통해 저장하지 않아도 메소드 호출로 간단하게 Bag에 추가해 줄 수 있습니다.

        Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { json in
                self.editView.text = json
                self.setVisibleWithAnimation(self.activityIndicator, false)
            })
            .disposed(by: self.disposeBag)