Swift “retry” logic on request

断了今生、忘了曾经 提交于 2019-12-03 06:04:38

问题


So i'm a bit lost on how to implement a retry logic when my upload request fail.

Here is my code i would like some guidance on how to do it

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()
        })
    }

回答1:


Here's a general solution that can be applied to any async function that has no parameters, excepting the callbacks. I simplified the logic by having only success and failure callbacks, a progress should not be that hard to add.

So, assuming that your function is like this:

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()
    })
}

A matching retry function might look like this:

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)
            }
        })
}

and can be called like this:

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

The above will retry the startUploading call three times if it keeps failing, otherwise will stop at the first success.

Edit. Functions that do have other params can be simply embedded in a closure:

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)")
    }
)



回答2:


Here is an updated answer for swift 3. I also added a generic object in the success block so if you make an object after your network call is complete you can pass it along to the final closure. Here is the retry function:

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)
    }
  }
}

And here is how you would use it if you updated a user and wanted to get back a new user object with the updated info:

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)
}


来源:https://stackoverflow.com/questions/34905900/swift-retry-logic-on-request

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!