Swift4のRxSwiftを使用して、非同期処理に失敗した場合にリトライするかどうか確認した後に再実行する


今日もSwift4!

非同期処理ありますよね、非同期処理。
例えばそれは外部通信だったり……いや、あれ、外部通信が9割9分9厘じゃないかな。

それはともかくとしてッ!
外部通信やら何やらに失敗したら、リトライするかどうか確認した後にもう一度チェックしたい! っていうことってあると思うんです。
RxSwiftのretryWhenを使用すると、そんな処理もキレイスッキリまとめられちゃうので、備忘録も兼ねてッ!

実装例!

retry.swift
// 何かしらの非同期処理を行う元ネタを用意
let o: Observable<Any> = Observable.create { observer in
    // とりあえずテスト用に毎回必ずエラーが起きるようにする
    observer.onError(TestError())
    return Disposables.create()
}

// retryWhenでリトライの条件を設定!
o.retryWhen({ (errors: Observable<Error>) in
    return errors.flatMap({ error -> Observable<Any> in
        let showAlert: Observable<Any> = Observable.create { observer in
            let action1 = UIAlertAction(title: "OK", style: .default, handler: { _ in
                // OKを押したら再実行!
                observer.onNext("🍛")
            })
            let action2 = UIAlertAction(title: "NG", style: .default, handler: { _ in
                // NGを押したらエラー実行でリトライ処理を抜ける!
                observer.onError(HogeError())
            })

            let alertController = UIAlertController(
                title: "", 
                message: "( ˘ω˘)", 
                preferredStyle: .alert
            )

            alertController.addAction(action1)
            alertController.addAction(action2)

            view.present(alertController, animated: true, completion: nil)

            return Disposables.create()
        }

        return showAlert
    })
}).subscribe(
    onNext: { _ in
        print("おめでとう👏")
    },
    onError: { _ in
        print("☠️")
    }
)

キレイスッキリまとめられると言いつつ、イマイチ記述が冗長な気もするけれども……
何はともあれとにかく、リトライ処理をRxSwiftにお任せして書くことができました