-
Rxswift operators - flatmap, flatmapLatest, merge개발/Swift 2022. 11. 11. 13:39
참조 : http://adamborek.com/thinking-rxswift/
Flatmap
검색결과에 따라 API 호출후
노래 리스트를 응답 받아 그려야하는 상황이다.
Observable<String> -> Observable<[Track]> -> Observable<[TrackRenderable]>:
그러면 이런 흐름으로 map operator를 사용하여Observable을 전달받아 처리하면 된다.
그러나 검색어에 대한 bservable<String> 은 동기적이고
Observable<[Track]> 은 API응답이므로 비동기적이다.
flatmap을 사용해 해결할수있다.
searchBar.rx.text.orEmpty.flatmap { query in return API.fetch(query:query) // Observable<Resutl> 리턴 해야함 }
Observable 을 응답값으로 받는 방법은 여기나와있다
http://adamborek.com/practical-introduction-rxswift/
FlatmapLatest
응답 딜레이에 따른 에러
- let 을 입력 → let 노래 리스트 요청
- let it go 입력 → let it go 노래 리스트 요청
- let it go 노래 리스트 응답
- let 노래 리스트 응답
이런경우 원하는 결과 값은 let it go 리스트 이지만 let 리스트가 결과적으로 받아오게 된다.
flatmaplatest를 사용하면 이전 구독을 모두 취소한다. 따라서 새 데이터가 오래된 응답에의해 대체될 수가 없게된다.
searchBar.rx.text.orEmpty.flatmapLatest { query in return API.fetch(query:query) // Observable<Resutl> 리턴 해야함 }.map { tracks in return tracks.map(TrackRenderable.init) } //Observable<[TrackRenderable]>
merge
만약 텍스트가 입력될때는 기존 리스트를 지우고 다시 받아오려한다면 어떻게 해야할까
기존에는 검색을 하면서 리스트가 수정 되겠지만 지우는 기능은 없다.
비어있는 노래 리스트를 리턴하는 Observable을 만들어
merge를 통해 합쳐주면 된다
//텍스트가 수정될때 let searchTextChanged = searchBar.rx.text.orEmpty.asObservable().skip(1) //기존 검색 로직 let tracksFromSpotify = searchTextChanged .flatMapLatest { query in return API.fetch(query:query) }.map { tracks in return tracks.map(TrackRenderable.init) } //지우는 로직 let clearTracksOnQueryChanged = searchTextChanged .map { _ in return [TrackRenderable]() } // 병합 let tracks = Observable.of(tracksFromSpotify, clearTracksOnQueryChanged).merge()
만약 Pullto Refresh를 여기다 구현한다 해보자.
refresh를 요청하면 마지막 searchtext를 가지고 쿼리를 해야한다.
let refreshControl = UIRefreshControl() tableView.addSubview(refreshControl) let didPullToRefresh: Observable<Void> = refreshControl.rx.controlEvent(.valueChanged) .map { [refreshControl] in return refreshControl.isRefreshing }.filter { $0 == true } .map { _ in return () } //refresh 끝나면 refreshControl.endRefreshing()
테이블뷰에 refresh control 을 넣어서 쉽게 사용할수있다.
기존에는 searchText가 바뀌면 쿼리했지만 이제는 merge를 통해 refresh 호출시에도 쿼리할것이다
여기서 Observable<String> (searchTextChanged) 의 마지막 값을 가져와야하는데
let refreshLastQuery = didPullToRefresh .withLatestFrom(searchTextChanged) //didPullToRefresh: Observable<Void> //searchTextChanged: Observable<String>
이렇게 사용할수 있다.
merge를 사용하면
let tracksFromSpotify = Observable.of(searchTextChanged, refreshLastQuery).merge() .flatMapLatest { query in return API.fetch(query:query) }.map { tracks in return tracks.map(TrackRenderable.init) }.do(onNext: { [refreshControl] _ in refreshControl.endRefreshing() })
이렇게 사용 가능하다.
'개발 > Swift' 카테고리의 다른 글
Rxswift 에러 핸들링 (complete, dispose 대응) (0) 2022.11.18 [Combine] - 1. publisher & subscriber (0) 2022.11.13 Combine Vs RxSwift (0) 2022.11.09 Apollo swift + Rxswift 를 활용한 API 네트워크와 에러처리 (0) 2022.11.03 [Swift] URLSession 통해 async fetch & json 파싱 (0) 2022.10.04