Jerry's Bakery

[RxSwift] Observable flatMap 사용법(API 호출 예제 포함) 본문

카테고리 없음

[RxSwift] Observable flatMap 사용법(API 호출 예제 포함)

_Jerry 2022. 6. 20. 23:31

flatMap이란?

ReactiveX에 있는 설명에 따르면 Observable으로 방출된 항목을 다시 다른 Observable로 방출하는 것입니다.

자체적으로 Observable이 있거나, 다른 방식으로 Observable로 변환할 수 있는 Observable이 있을 때 유용하게 사용할 수 있습니다.

더 자세한 설명은 아래 링크를 참조해주시면 감사드리겠습니다.

 

ReactiveX - FlatMap operator

<!-- TODO: flatMapFirst, flatMapWithMaxConcurrency, selectSwitchFirst, selectWithMaxConcurrent https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/flatmapfirst.md https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/co

reactivex.io

 

본 글에서는 flatMap을 사용하여 SearchBar입력값으로 API 호출을 진행하는 프로젝트를 진행해 보겠습니다.

프로젝트 링크는 아래와 같습니다.

 

GitHub - noh3310/FlatMapProject

Contribute to noh3310/FlatMapProject development by creating an account on GitHub.

github.com

APIManager

API를 호출하는 코드입니다.

RxAlamofire를 사용해 Observable<[Repos]>를 리턴하는 함수입니다.

func apiCall(_ str: String) -> Observable<[Repos]> {

    let parameters: Parameters = [
        "q": str
    ]

    return RxAlamofire.requestData(.get, URL(string: "https://api.github.com/search/repositories")!, parameters: parameters)
        .map { (response, data) in
            do {
                let decoder = JSONDecoder()
                let result = try decoder.decode(ReposResult.self, from: data)
                return result.items
            } catch {
                return []
            }
        }
}

ViewModel

ViewModel 클래스는 searchBar값을 바인딩하는 searchText변수와, API 결괏값을 담고 있는 result 값을 담고 있는 result 두 변수를 가지고 있습니다.

let searchText = BehaviorRelay<String>(value: "")
let result = PublishRelay<[Repos]>()

아래 코드에서 searchText의 값이 변경될 때 flatMap을 사용해 API를 호출합니다.

호출된 API는 Observable<[Repos]>를 리턴하고, 리턴된 Observable을 구독해 [Repos]를 result에 Accpet 합니다.

searchText
    .flatMap { self.apiManager.apiCall($0) }   // Observable<[Repos]> 리턴
    .subscribe(onNext: { self.result.accept($0) })
    .disposed(by: disposeBag)

View

searchBar의 입력값을 ViewModel의 searchText에 바인딩합니다.

searchBar.rx.text.orEmpty
    .bind(to: viewModel.searchText)
    .disposed(by: disposeBag)

viewModel의 result를 구독하고, 결괏값을 tableView에 바인딩합니다.

viewModel.result
    .bind(to: tableView.rx.items(cellIdentifier: "cell")) { (indexPath, cellViewModel, cell) in
        if #available(iOS 14.0, *) {
            var config = cell.defaultContentConfiguration()
            config.text = cellViewModel.fullName

            cell.contentConfiguration = config
        } else {
            cell.textLabel?.text = cellViewModel.fullName
        }
    }
    .disposed(by: disposeBag)
Comments