안녕하세요 피터입니다 😃
오늘은 RxSwift에서 flatMap
과 withLatestFrom
연산자의 차이와 사용 시점에 대해 알아보겠습니다.
멘토링 도중, Swift의 RxSwift를 사용하여 비동기 프로그래밍을 구현하던 중, PublishRelay
를 사용하여 email과 password 데이터를 처리하던 중 데이터가 이벤트로 제대로 넘어오지 않는 문제가 발생했습니다. 구체적으로는 다음과 같은 코드였습니다.
//input
let text1 = PublishRelay<String>()
let text2 = PublishRelay<String>()
let buttonTapped = PublishRelay<Void>()
lazy var result = buttonTapped
.flatMap { _ in
Observable.combineLatest (self.text1, self.text2) }
.flatMap { text1, text2 in
Service().doSomething(a: text1, b: text2)
}
이 코드에서는 버튼이 탭될 때마다 text1
과 text2
의 최신 값을 가져와서 Service().doSomething(a:b:)
함수를 호출하고자 했습니다. 그런데 debug()
를 통해 확인해보니 text1
과 text2
에서 데이터가 방출되지 않는 문제가 있었습니다.
정의: Observable에서 나오는 item들을 Observables로 변환시켜주고 single Observable로 flatten하게 방출시켜준다.
즉, 버튼을 탭할때마다
Observable.combineLatest (self.text1, self.text2)
의 Observable로 변환시켜주는 것이고
버튼을 탭한 시점에는
text1과 text2에서 String 이벤트가 없기 때문에 반응이 없었던 것이다.
하지만 그 이후에 text1과 text2에서 이벤트가 방출되면
(위 그림을 참고하자면)
빨간색, 초록색, 파란색 버튼 탭에 해당하는 각각의 Observable.combineLatest (self.text1, self.text2)의 이벤트가 나오기 때문에
어떻게 보면 동일한 이벤트가 우수수 떨어지는 (여러 개의 스트림이 존재하는) 위험한 상황까지 올 수 있다.
withLatestFrom
연산자는 다른 Observable의 최신 아이템을 선택하여 함께 방출하는 연산자입니다.
정의를 보다 쉽게 이해하도록 예시를 들자면: 버튼을 클릭할 때마다 해당 시점에 text1
과 text2
에서 가장 최신의 데이터를 가져와 합쳐서 방출하는 것입니다.
따라서, 버튼을 클릭할 때마다 미리 text1
과 text2
에서 방출된 가장 최근의 아이템을 가져와서 사용하는 것입니다. 이것이 바로 withLatestFrom
연산자의 핵심입니다.
text1
과 text2
에서 아무런 이벤트가 발생하지 않으면 반응이 없습니다. 그리고 나중에 이벤트가 발생하면 해당 Observable 스트림에서 여러 개의 이벤트가 방출될 위험이 있습니다.text1
과 text2
의 최신 값을 즉시 가져올 수 있습니다.결과적으로, 이 문제에서는 flatMap
을 사용하면 예상한 대로 동작하지 않았지만, withLatestFrom
을 사용하면 원하는 시점의 최신 값을 즉시 가져와서 처리할 수 있습니다.
이 설명이 문제의 이해와 해결에 도움이 되었기를 바랍니다! 😃