web-dev-qa-db-ja.com

Swift「再試行」ロジックはリクエストに応じて

そのため、アップロード要求が失敗したときに再試行ロジックを実装する方法に少し迷っています。

これが私のコードですそれを行う方法についてのガイダンスが欲しいです

func startUploading(failure failure: (NSError) -> Void, success: () -> Void, progress: (Double) -> Void) {
        DDLogDebug("JogUploader: Creating jog: \(self.jog)")

        API.sharedInstance.createJog(self.jog,
            failure: { error in
                failure(error)
            }, success: {_ in
                success()
        })
    }
14
Luis

これは、コールバックを除いて、パラメーターを持たないすべての非同期関数に適用できる一般的なソリューションです。 successfailureのコールバックだけを使用してロジックを簡略化しましたが、progressを追加するのはそれほど難しくありません。

したがって、関数が次のようになっていると仮定します。

func startUploading(success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
    DDLogDebug("JogUploader: Creating jog: \(self.jog)")

    API.sharedInstance.createJog(self.jog,
        failure: { error in
            failure(error)
        }, success: {_ in
            success()
    })
}

一致するretry関数は次のようになります。

func retry(times: Int, task: (success: @escaping () -> Void, failure: @escaping (Error) -> Void) -> Void, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
    task(success: success, 
        failure: { error in
            // do we have retries left? if yes, call retry again
            // if not, report error
            if times > 0 {
                retry(times - 1, task: task, success: success, failure: failure)
            } else {
                failure(error)
            }
        })
}

そしてこのように呼ぶことができます:

retry(times: 3, task: startUploading,
    success: {
        print("Succeeded")
    },
    failure: { err in
        print("Failed: \(err)")
})

上記は、失敗し続ける場合はstartUploading呼び出しを3回再試行し、それ以外の場合は最初の成功で停止します。

編集。他のパラメータを持つ関数は、クロージャに簡単に埋め込むことができます。

func updateUsername(username: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
    ...
}

retry(times: 3, { success, failure in updateUsername(newUsername, success, failure) },
    success: {
        print("Updated username")
    },
    failure: {
        print("Failed with error: \($0)")
    }
)
22
Cristik

Swift 3.の更新された回答は次のとおりです。また、成功ブロックにジェネリックオブジェクトを追加したので、ネットワーク呼び出しの完了後にオブジェクトを作成すると、それを最終的なクロージャに渡すことができます。再試行機能は次のとおりです。

func retry<T>(_ attempts: Int, task: @escaping (_ success: @escaping (T) -> Void, _ failure: @escaping (Error) -> Void) -> Void, success: @escaping (T) -> Void, failure: @escaping (Error) -> Void) {
task({ (obj) in
  success(obj)
}) { (error) in
  print("Error retry left \(attempts)")
  if attempts > 1 {
    self.retry(attempts - 1, task: task, success: success, failure: failure)
  } else {
      failure(error)
    }
  }
}

また、ユーザーを更新し、更新された情報で新しいユーザーオブジェクトを取得したい場合は、次のように使用します。

NetworkManager.shared.retry(3, task: { updatedUser, failure in
NetworkManager.shared.updateUser(user, success: updatedUser, error: failure) }
, success: { (updatedUser) in
  print(updatedUser.debugDescription)
}) { (err) in
  print(err)
}
5
JustinM