RxSwift - 알아보기Transforming Operator Operator<Map,FlatMap>

JSLee·2022년 2월 16일
0

변환 Operator(연산자)

이전 포스팅에서 설명하였던 생성 Operator가 아닌 이번 포스팅에서는
Observable이 방출(Emit) 하는 Data 의 값을 변환(Transform)하는 Operator에 대해서 설명하려고 합니다!🙋🏻‍♂️

ReactiveX 의 Document 에서 발췌한 내용입니당!!
일단 설명을 보자면 Rx는 구현간 겹치는 연산자들이 많이 있지만 특정 구현에서만 사용 할수 있는 연산자 또한 존재한다고 합니다.그리고 연산자의 이름 또한 우리가 자주 사용했던 Method 들과 이름이 흡사하기도 하다고 하네요. 일단 하나씩 살펴 보도록 하겠습니다.

Map

map은 기본적으로 Swift에도 있는 Method 라고 알고있지요.
Rx에서의 map 도 비슷한 로직을 수행합니다.

각 항목에 함수를 적용하여 Observable에서 내보내는 항목을 변환합니다.

구현

Observable.from([1,2,3]).map { $0 * 2 }.subscribe(onNext: { print( $0 ) } ).disposed(by: disposeBag)

이런식 의 구현이 가능합니다.
또한 만약 from 안에 있는 값들이 Int가 아닌 String 이여도 map 안에서 형변환을 통해서 타입을 바꾸고 연산을 실행할수도 있습니다.

FlatMap

Observable에 의해 방출된 항목을 Observable로 변환한 다음 그 방출을 단일 Observable로 평면화합니다.

  • 빨간색 원을 방출하는 Observable 을 FlatMap이 빨간색 다이아몬드를 방출하는 Observable로 변환 한다.

  • FlatMap은 방출된 시퀀스의 값이 변경되면 새로운 값을 방출하는 시퀀스를 방출한다.

  • 처음 방출하는 Observable의 값을 계속 감시하고 최신 값을 확인할수 있다.

  • 원(개별 시퀀스) 들이 FlatMap(개별 Observable)이 되었다가 다이아몬드(하나의 Observable)로 변환된다.

예시를 통해 한번더 알아보자!!

기본 예제

        let sequenceInt = Observable.of(1, 2, 3)
        let sequenceString = Observable.of("A", "B", "C", "D")
        sequenceInt
            .flatMap { (x: Int) -> Observable<String> in
                print("Emit Int Item : \(x)")
                return sequenceString
            }
            .subscribe {
                print($0)
            }.disposed(by: disposeBag)
//print
Emit Int Item : 1
next(A)
Emit Int Item : 2
next(B)
next(A)
Emit Int Item : 3
next(C)
next(B)
next(A)
next(D)
next(C)
next(B)
next(D)
next(C)
next(D)
completed

Operator 의 이해도 를 올리기 위해 실제 사용예제를 살펴보면

예를 들어 URL 주소값을 통해서 이미지를 불러온다고 하였을 경우를 생각해보면

let imageUrl = "https://이미지 Url..."
Observable.just(imageUrl)
.map { URL(string: $0 ) }
....
....

이런식으로 Map 을 통해서 String을 URL로 변경해주고 ....
URL 이미지를 함수를 통해 가져온다고 하였을때
그 함수는 Void 타입이

Observable<UIImage>

라고 가정하면!

let imageUrl = "https://이미지 Url..."
Observable.just(imageUrl)
.map { URL(string: $0 ) }
.map { ImageLoad함수($0) } 

이렇게 될텐데 이경우에 Observabled의 타입이

let imageUrl = "https://이미지 Url..."
Observable.just(imageUrl) //Observable<String>
.map { URL(string: $0 ) } //Observable<URL>
.map { self.ImageLoad함수($0) } //Oservable<Observable<UIImage>> 

이렇게 되는 상황이 발생하게 된다
물론 다른 방법으로 할수도 있지만 Image를 Load하는 함수를 따로 만들어 관리하는것이 로직상으로 보았을때 좀더 관리하기 쉽기 때문에 Load함수는 포기할수 없는 상황이다.
이때 flatMap을 사용하면 된다

let imageUrl = "https://이미지 Url..."
Observable.just(imageUrl) //Observable<String>
.map { URL(string: $0 ) } //Observable<URL>
.flatMap { self.ImageLoad함수($0) } //Oservable<UIImage> 

그럼 조금더 쉬운 예제

let array = [1,2,3] 
array.map { [$0 * 2 , $0 * 3] } 

이러한 작업을 수행한다고 했을때

//print
[2,4,6],[3,6,9]

이런 식으로 출력이 될것이다.
하지만 flatMap을 사용하게 되면

let array = [1,2,3] 
array.flatMap { [$0 * 2 , $0 * 3] } 
//print
2,4,6,3,6,9

이렇게 하나의 흐름으로 방출되게 된다

위의 이미지를 보게되면 조금더 쉽게 이해할수 있을것 같다.

profile
iOS/Android/FE/BE

0개의 댓글