flatMap Operator에 대하여(RxSwift)

1 분 소요

flatMap에서 error가 담긴 Observable이 반환되는 경우

여태까지 나는 ‘flatMap을 통해 반환되는 Observable이 기존 시퀀스에는 전혀 영향을 미치지 않는다.’라고 생각해왔다. (왜그랬는지는 모르겠다. 아마도 처음에 어렵다고 느껴서 나 혼자서 이렇게 정의내렸던 것 같다.)

_ = button.rx.tap.debug("TAP")
            .flatMap {
                return Observable<Int>.error(TestError.fakeError).debug("내부 Observable")
            }.debug("flatMap 이후")
            .subscribe()
//여기서는 스스로 dispose되는지 확인만 하면 되므로 굳이 disposeBag에는 넣지 않았다. 

enum TestError: Error {
        case fakeError
    }

위 코드를 예시로 들어보겠다.
이전의 나: “flatMap에서 error를 확정적으로 가지는 Observable을 반환한다고 해도.. 어차피 button에 대한 Observable과는 다른 별도의 시퀀스이니 서로 영향은 없겠네. 버튼 탭할때마다 에러 메시지가 나오려나?” 내가 예상했던 스트림 전개는 아래와 같았다.

TAP             --T--------T--------T-----....---->     
내부 Observable  --X->    --X->    --X-> 
flatMap 이후     --X->    --X->    --X->

flatMap 이후에 대한 스트림이 끊긴다고는 하더라도 TAP 부분에 있는 기존 시퀀스는 안끊기고 계속 살아있을 것으로 생각했다.

그런데 위의 내 생각은 잘못된 것이었다.
flatMap에서 반환되는 Observable이 error를 지니고 있다면 이는 기존의 시퀀스에도 영향을 미친다.

TAP             --T-|>      
내부 Observable  --X->
flatMap 이후     --X->

위와같이 말이다.

위의 테스트 코드를 실행한 로그 출력은 아래와 같았다.

flatMap 이후 -> subscribed
TAP -> subscribed
//탭 버튼을 누름
TAP -> Event next(())
내부 Observable -> subscribed
내부 Observable -> Event error(fakeError)
flatMap 이후 -> Event error(fakeError)
Unhandled error happened: fakeError  //error가 기존 시퀀스에도 영향을 미친다. 
flatMap 이후 -> isDisposed
TAP -> isDisposed
내부 Observable -> isDisposed

참고한 사이트: RxSwift Github Issue

 

flatMap 내에서 반환되는 Observable이 subscribe 되는 시점

_ = button.rx.tap.debug("TAP")
            .flatMap {
                return BehaviorRelay(value: Int.random(in: 0...100)).debug("내부 Observable").take(1)
            }.debug("flatMap 이후")
            .subscribe()

결과 출력

flatMap 이후 -> subscribed
TAP -> subscribed
//버튼을 누름
TAP -> Event next(())
내부 Observable -> subscribed
내부 Observable -> Event next(34)
flatMap 이후 -> Event next(34)
내부 Observable -> isDisposed

flatMap에서 반환되는 Observable은 처음부터 subscribe되는 것이 아니다. 본격적으로 스트림이 시작되고 flatMap이 작동하는 시점에 subscribe된다.

더 중요하게 살펴봐야 할 것은 error 때 와는 다르게 정상 작동이 된 경우 기존(전체) 시퀀스가 종료되지 않는다는 점이다.

내부 Observable에 BehaviorRelay를 넣고 take(1)을 해줬는데, 사실 Observable.just()를 사용해도 된다. 다만 take를 쓰는 이유를 같이 체크해보고자 사용해보았다. take Operator에 대한 글(RxSwift)

카테고리:

업데이트:

댓글남기기