Post

flatMap vs flatMapLatest with RxSwift-Combine

RxSwift

flatMap 과 flatMapLatest

공통점은 앞에 이벤트를 받아서 뒤로 전달하는 기능으로

보통 API에 호출 결과물로 이어서 작업할때 자주 사용한다.

차이점은 아래와 같다.

flatMap

아래 코드는 버튼 탭을 하면 Int 값을 전달하는 Observalble 을 생성가고, 그걸 구독하고 있다.

두번 탭을 통해 스트림 여러개가 누락없이 전부 오는것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
testBtn.rx.tap
            .scan(0) { aNumber, _ -> Int in
                print("tapped")
                return aNumber + 1
            }.flatMap { tapNumber -> Observable<Int> in
                Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
                    .do(onNext: { intervalNumber in
                        print(#line, "tapNumber: \(tapNumber) - inervalNumber: \(intervalNumber)")
                    })
            }.subscribe(onNext: { intervalNumber in
                // print(#line, "- \(intervalNumber)") (보기 편하게 주석 처리함)
            }).disposed(by: distposeBag)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tapped  
44 tapNumber: 1 - inervalNumber: 0
44 tapNumber: 1 - inervalNumber: 1
44 tapNumber: 1 - inervalNumber: 2
44 tapNumber: 1 - inervalNumber: 3
tapped 두번째 
44 tapNumber: 1 - inervalNumber: 4
44 tapNumber: 2 - inervalNumber: 0
44 tapNumber: 1 - inervalNumber: 5
44 tapNumber: 2 - inervalNumber: 1
44 tapNumber: 1 - inervalNumber: 6
44 tapNumber: 2 - inervalNumber: 2
44 tapNumber: 1 - inervalNumber: 7
44 tapNumber: 2 - inervalNumber: 3
44 tapNumber: 1 - inervalNumber: 8

flatMapLatest

동일하게 두번 탭을 해서 Observable 이 2개 생성되었지만

최신 생성한 두번째 탭 이벤트만 전달 하는걸 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
testBtn.rx.tap
                    .scan(0) { aNumber, _ -> Int in
                        print("tapped")
                        return aNumber + 1
                    }.flatMapLatest { tapNumber -> Observable<Int> in
                        Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
                            .do(onNext: { intervalNumber in
                                print(#line, "tapNumber: \(tapNumber) - inervalNumber: \(intervalNumber)")
                            })
                    }.subscribe(onNext: { intervalNumber in
                        // print(#line, "- \(intervalNumber)")
                    }).disposed(by: distposeBag)
1
2
3
4
5
6
7
8
9
10
11
tapped  
57 tapNumber: 1 - inervalNumber: 0
57 tapNumber: 1 - inervalNumber: 1
57 tapNumber: 1 - inervalNumber: 2
57 tapNumber: 1 - inervalNumber: 3
tapped 두번째 
57 tapNumber: 2 - inervalNumber: 0
57 tapNumber: 2 - inervalNumber: 1
57 tapNumber: 2 - inervalNumber: 2
57 tapNumber: 2 - inervalNumber: 3
57 tapNumber: 2 - inervalNumber: 4

Combine

flatMap

RxSwift 와 동일하게 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
testBtn.tapPublisher
                    .handleEvents(receiveOutput: {
                        print("tapped")
                    })
                    .scan(0) { aNumber, _ -> Int in
                        return aNumber + 1
                    }
                    .flatMap { tapNumber -> AnyPublisher<Int, Never> in
                        Timer.publish(every: 1, on: .main, in: .common).autoconnect()
                            .scan(0) { aNumber, _ -> Int in
                                return aNumber + 1
                            }
                            .handleEvents(receiveOutput: { intervalNumber in
                                print(#line, "tapNumber: \(tapNumber) - intervalNumber: \(intervalNumber)")
                            }).eraseToAnyPublisher()
                    }
                    .sink(receiveValue: { intervalNumber in
                        //print(#line, "- \(intervalNumber)")
                    }).store(in: &subscriptions)
1
2
3
4
5
6
7
8
9
10
11
12
13
tapped
77 tapNumber: 1 - intervalNumber: 1
77 tapNumber: 1 - intervalNumber: 2
77 tapNumber: 1 - intervalNumber: 3
77 tapNumber: 1 - intervalNumber: 4
tapped
77 tapNumber: 1 - intervalNumber: 5
77 tapNumber: 2 - intervalNumber: 1
77 tapNumber: 1 - intervalNumber: 6
77 tapNumber: 2 - intervalNumber: 2
77 tapNumber: 1 - intervalNumber: 7
77 tapNumber: 2 - intervalNumber: 3
77 tapNumber: 1 - intervalNumber: 8

flatMapLatest

flatMap → map 으로 변경

.sink 위에 .switchToLatest() 를 추가 해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
testBtn.tapPublisher
                    .handleEvents(receiveOutput: {
                        print("tapped")
                    })
                    .scan(0) { aNumber, _ -> Int in
                        return aNumber + 1
                    }
                    .map { tapNumber -> AnyPublisher<Int, Never> in
                        Timer.publish(every: 1, on: .main, in: .common).autoconnect()
                            .scan(0) { aNumber, _ -> Int in
                                return aNumber + 1
                            }
                            .handleEvents(receiveOutput: { intervalNumber in
                                print(#line, "tapNumber: \(tapNumber) - intervalNumber: \(intervalNumber)")
                            }).eraseToAnyPublisher()
                    }
                    .switchToLatest()
                    .sink(receiveValue: { intervalNumber in
                        //print(#line, "- \(intervalNumber)")
                    }).store(in: &subscriptions)
1
2
3
4
5
6
7
8
9
10
tapped
98 tapNumber: 1 - intervalNumber: 1
98 tapNumber: 1 - intervalNumber: 2
98 tapNumber: 1 - intervalNumber: 3
98 tapNumber: 1 - intervalNumber: 4
tapped
98 tapNumber: 2 - intervalNumber: 1
98 tapNumber: 2 - intervalNumber: 2
98 tapNumber: 2 - intervalNumber: 3
98 tapNumber: 2 - intervalNumber: 4
This post is licensed under CC BY 4.0 by the author.

Trending Tags