RxSwift를 이용한 연습 프로젝트를 진행하면서
종종 두뇌 CPU 사용량 초과로 뇌정지가 왔는데 😵💫
그럴 때 가장 자주 헤맸던 부분이 map
과 flatMap
의 사용이었다.
map
flatMap
이번 프로젝트에서 subcribe
전까지의 stream 가공에서 가장 많이 썼던 요것들...
다시는 얘네 앞에서 뇌정지가 오지 않도록 정리를 해보겠다.
즉, Observable이 가진 요소들에 특정 연산을 수행한다.
1, 2, 3
을 요소로 가진 Observable에 .map{ $0 * 2 }
를 실행하면
2, 4, 6
을 요소로 가진 Observable이 되는 것이다.
Observable<Int>
.of(1, 2, 3)
.map{ $0 * 2 }
여기에 subscribe를 하면 Int 타입 요소들이 방출된다.
공식문서:
Observable에 의해 방출된 항목을 Observable로 변환한 다음 그 방출을 단일 Observable로 평면화합니다.
Observable의 요소들을 각각의 Observable로 만들고, 만들어진 각각의 Observable이 요소들을 방출하게 된다.
🤔❓🤔❓🤔❓🤔❓🤔❓
1, 2, 3
을 요소로 가진 Observable에 .flatMap{ $0 * 2 }
를 실행하면
2, 4, 6
을 각각의 요소로 가진 3개의 Observable이 되며 이 Observable들이 요소를 방출하고, 그것을 다시 하나의 Observable로 방출된다...?
❓🤔❓🤔❓🤔❓🤔❓🤔
...라고 쓰면서 아니 그러면 map하고 다른게 뭐야...? 요소들을 Observable로 나눴다가 다시 하나의 Observable로 만들면 뭐가 다른건데...뭘 한 건데...뭔데...
라는 생각이 들었다...
그래서 조금 더 공부를 해봤더니
💡
flatMap은
1. 한번에 여러 스트림을 사용할 수 있다.
2. 여러 스트림에서 방출된 아이템에 대해 누락 없이 구독이 가능하다.
라는 장점이 있었다.
observable1
의 요소: "A"
, "B"
, "C"
observable2
의 요소: "a"
, "b"
, "c"
이렇게 두개의 스트림이 있고 "Aa", "Ab", "Ac", "Ba"....을 가진 Observable을 얻고 싶을 때 아래와 같은 작업이 가능하다.
observable1
// 1.
.flatMap{ uppercase: String -> Observable<String> in
// 2.
return observable2.map{ uppercase + $0 }
}
observable1
의 각 요소 uppercase
들을 이용해서 flatMap
을 할것이다.observable2.map
을 통해서 observable2
의 각 요소에 uppercase
를 합친 것을 새로운 요소로 갖는 observable이 리턴된다.Observable이 3개
가 된다.평면적으로 합쳐진다
.flatMap은 하나의 스트림을 가공하는 클로저 내부에서 또 다른 스트림을 사용할 때 편리하다!
subsribe를 하지 않고 observable의 요소들을 이용할 수 있고, 결과를 리턴값으로 사용할 수도 있다. (do를 쓰면 스트림의 요소들을 사용할 수는 있겠지만 리턴값으로 사용은 어렵다.)
Observable<Observable<Observable<String>>>
같은 끔찍한 리턴 타입을 목격한다던가...(경험담)
연습 프로젝트에서 활용해본 사례로는
let strawBananaJuiceMakingResult = input.strawBananaJuiceButtonDidTap
.flatMap{ self.juiceMaker.juiceMakingResult(.strawberryBananaJuice) }
위와 같은 코드가 있었다.
input.strawBananaJuiceButtonDidTap
는 Observable<Void>
타입이고,
flatMap 클로저 내부의 juiceM akingResult
메소드는 Observable<Bool>
타입을 반환한다.
input.strawBananaJuiceButtonDidTap
에서 방출되는 Void 타입 요소를 self.juiceMaker.juiceMakingResult(.strawberryBananaJuice)
를 통해 Observable<Bool>
로 만들고, 만들어진 이 Observable 또한 요소를 방출한다.
그리고 flatMap을 통해 Observable들을 하나로 평평하게 만들어서 방출된다.
그 결과 Observable<Bool>
타입을 갖게 되었다.