subscribe

비동기 요청을 위한 stream을 생성하기 위해 Observable을 보면 여러가지 operator가 존재하는 걸 알 수 있는데, 그중 가장 중요한 subscribe()와 dispose()를 알아보자. 

지난번 Rxswift로 작성된 코드를 보면 Subscribe()와 disposed()로 마무리가 되어있는걸 확인 할 수 있다. 

var disposebag = DisposeBag()
@IBAction func onLoadRxAsync(_ sender: Any) {
    Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
        .disposed(by: disposebag)
}

그렇다면 subscribe는 무엇일까? 

func subscribe(onNext: ((_) -> Void)? = nil,
	onError: ((Error) -> Void)? = nil, 
	onCompleted: (() -> Void)? = nil, 
	onDisposed: (() -> Void)? = nil) -> Disposable
The Subscribe operator is the glue that connects an observer to an Observable. In order for an observer to see the items being emitted by an Observable, or to receive error or completed notifications from the Observable, it must first subscribe to that Observable with this operator.

Observerble과 Observer사이를 연결해주는 operator라고 한다. Observer와 연결하게 되면서 Observable이 아이템을 방출하거나, 에러 혹은 완료를 알림받게 된다. 즉 Observerble이 발생시키는 이벤트들을 확인할 수 있는 operator인 것이다. 

 

Disposable

그렇다면 subscribe()의 리턴값인 Disposable은 무엇일까? 

Observable에서 구독(subscribe)받는 이벤트들은 처분(dispose)할 시점이 반드시 오게된다. 즉 Disposable은 dispose가능한 자료형의 형태로 보면된다. (먼저 구독을 해야 처분을 받을수 있으니)

이 얘기는 subscribe를 통해 작업이 일어나는 도중, 임의의 시점에 강제로 처분(dispose)이 가능하다는 얘기이다.

@IBAction func onLoadRxAsync(_ sender: Any) {
    self.imageView.image = nil
        
    let disposable = Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
}

즉 예시와 같이 처분가능한(disposable)형태로 담아둘수 있다는 이야기이고, 이를 전역변수에 담아두게된다면 다른 함수호출을 통해 요청취소가 가능하다는 이야기이다. 

var disposable: Disposable?
@IBAction func onLoadRxAsync(_ sender: Any) {
    self.imageView.image = nil
        
    disposable = Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
}

 

Disposebag()

여러개의 Disposable을 처리하기 위해 Disposablebag을 활용할 수 있다.

var disposebag = DisposeBag()
    
@IBAction func onLoadRxAsync(_ sender: Any) {
    self.imageView.image = nil
        
    let disposable = Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
    disposebag.insert(disposable)
}

insert메소드를 통해 추가가 가능하며, 예시처럼 단일형태의 Disposable도 가능하지만, 배열형태나, 범위의 형태로도 추가 가능하다.

추가로 같은 동작을 조금 더 간결하게 작성하는 것도 가능하다. disposable에 속해있는 disposed(by:) 메소드를 사용하면 자기자신을 Disposablebag에 추가한다.

func disposed(by bag: DisposeBag){
    //Adds self to bag
    //bag: DisposeBag to add self to.
}
var disposebag = DisposeBag()
    
@IBAction func onLoadRxAsync(_ sender: Any) {
    self.imageView.image = nil
        
    Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
        .disposed(by: disposebag)
}

그렇게 처음에 적힌 예시코드와 같은 형태로 완성이 된다. 

var disposebag = DisposeBag()
    
@IBAction func onLoadRxAsync(_ sender: Any) {
    self.imageView.image = nil
        
    Observable.just(self.IMAGE_URL)
        .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .default))
        .map{self.loadImage(from: $0)}
        .observe(on: MainScheduler.instance)
        .subscribe(onNext: { image in
            self.imageView.image = image
        })
        .disposed(by: disposebag)
}
@IBAction func cancelRxAsync(_ sender: Any) {
    disposebag = DisposeBag()
}

Disposebag을 사용하여 작업을 취소하는 방법은 간단하다. 원하는 시점에 Disposebag을 초기화만 해주면 된다. 

취소버튼을 통해 작업을 취소하는 모습을 확인 할 수 있다.

 

참고영상

[유튜브] 곰튀김 RxSwift 4시간에 끝내기 - 3

 

'iOS > RxSwift' 카테고리의 다른 글

scheduler  (0) 2022.08.31
next, error, complete  (0) 2022.08.19
operator  (0) 2022.07.21
Observable stream  (0) 2022.06.08
ReactiveX  (0) 2022.05.30

+ Recent posts