Open1
Combine 非同期処理中のloading stateを楽に管理できるextension
ボタンを押されたらイベントが発火し、それに応じてflatMapでFutureを返す通信処理を実行するみたいなやつで二重送信を防ぎたい
かつフォームに送信中であるという状態を露出したい(Activity Indicator出したりボタンをdisabledにしたり)
毎回手続き型っぽい書き方するの嫌だな〜と思って書いたextensionがこちら
extension Publisher {
func flatMap<T, P>(withLoading loading: CurrentValueSubject<Bool, Never>, maxPublishers: Subscribers.Demand = .unlimited, _ transform: @escaping (Self.Output) -> P) -> AnyPublisher<P.Output, P.Failure> where T == P.Output, P: Publisher, Self.Failure == P.Failure {
filter { _ in !loading.value }
.handleEvents(receiveOutput: { _ in loading.send(true) })
.flatMap(transform)
.handleEvents(receiveOutput: { _ in loading.send(false) })
.eraseToAnyPublisher()
}
}
使用例
let submitting = CurrentValueSubject<Bool, Never>(false)
// バリデーション結果とcombineLatestしてbuttonのdisabledにbindしたりできる
let canSubmit = submitting.map { !$0 }
let result = onTapSubmit
.flatMap(withLoading: submitting) {
submit().receive(on: DispatchQueue.main)
}.share()
イケてないところ
-
返り値がAnyPublisherになる
Publishers.FlatMapのまま返すことはできないのでFlatMapWithLoadingみたいな型を作る?
それやるくらいならAnyPublisherでいい気はする -
filter { _ in !loading.value }
RxSwiftで言うところのwithLatestFromがCombineにないのでしゃーなし!独自実装してもいいんですけどね
もっと良い書き方あればマサカリお願いします