Fast "repeat" logic on demand

So, I lost a bit how to implement the retry logic when my download request failed.

Here is my code, I would like some recommendations on how to do this

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() }) } 
+11
source share
2 answers

Here's a general solution that can be applied to any asynchronous function that has no parameters, except for callbacks. I simplified the logic, having only success and failure , progress should not be so complicated.

So, suppose your function looks 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() }) } 

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

Above will repeat the startUploading call three times if it continues to fail, otherwise it will stop on the first success.

Edit Functions that have other parameters can simply be built into the 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)") } ) 
+19
source

Here is an updated answer for quick 3. I also added a shared object to the success block, so if you make an object after the network call ends, you can pass it on until it is finally closed. Here is the snooze 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 could use it if you updated the user and wanted to return a new user object with the updated information:

 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
source

All Articles