RxSwiftをasync/awaitに変換する
RxSwiftをasync/awaitに変換する
はじめに
RxSwiftを使っている中で、async/awaitに変換して使いたい時があります。
具体的な場面としては、refreshable View Modifierでasync/awaitを使いたい時があります。
func refreshable(action: @escaping () async -> Void) -> some View
refreshable
View Modifierでは、非同期関数を実行することができ、インジケータと同期されています。
成功時
エラー時
(非同期関数の実行結果を受け取ってからインジケータが非表示になります)
refreshable
View Modifierで同期関数を実行すると、レスポンス待ちなのですが、インジケータが一回表示されて、インジケータは非表示になります。
実装方法
RefreshableSampleView.swift
protocol RefreshableSampleViewProtocol: AnyObject {
func refresh() async
}
struct RefreshableSampleView: View {
// ...
var body: some View {
switch dataSource.viewState {
case .success:
successView()
case .failed:
failedView()
}
}
var successView: some View {
ScrollView {
Text("Hello World!")
}
.refreshable {
await delegate?.refresh()
}
}
var failedView: some View {
Text("Error")
}
}
Viewのコードでは、delegateメソッドを利用し、VCにロジックを寄せています。
refreshable View Modifier内で非同期関数を呼んでいます。
RefreshableSampleViewController.swift
final class RefreshableSampleViewController: UIViewController {
// ...
}
extension RefreshableSampleViewController: RefreshableSampleViewProtocol {
func refresh() async {
// pull to refreshで実行されるAPIを叩く
viewModel.inputs.refreshTrigger.accept(())
// didRefresh: Driver<Void>を受け取る
for await value in viewModel.outputs.didRefresh.values { return }
}
}
ViewControllerのコードでは、Delegateプロトコルに準拠し、refresh
非同期関数を実装しています。
最初にpull to refreshで実行されるAPIを叩きます。
次に、Driver<Void>型のプロパティをawaitを用いて値を取り出せるように待ちます。
値を取得できると、Viewのインジケータも閉じられるようになります。
(APIから取得した値は、省略していますが別途ViewModelから受け取るようにしています)
まとめ
RxSwiftのDriver
をrefreshable
View Modifier内でasync/awaitに変換することができるようになりました。
RxSwiftのDriver
・Single
では、例外処理が発生しないので、(エラーをスローしないので)VCやViewのロジックで例外処理を実装する必要がなさそうです。
Discussion