2016-01-20 2 views
6

Quindi sono un po 'perso su come implementare una logica di riprova quando la mia richiesta di upload fallisce.Logica "riprova" rapida su richiesta

Ecco il mio codice vorrei alcune indicazioni su come farlo

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

Partenza mia risposta per una domanda simile: http://stackoverflow.com/a/38720898/319805 – MNassar

risposta

14

Ecco una soluzione generale che può essere applicata a qualsiasi funzione asincrona che non ha parametri, eccetto i callback. Ho semplificato la logica avendo solo success e failure richiamate, un progress non dovrebbe essere così difficile da aggiungere.

Quindi, partendo dal presupposto che la funzione è come questo:

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

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

Un retry funzione di corrispondenza che sarebbe simile a questa:

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

e può essere chiamato in questo modo:

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

Quanto sopra riproverà la chiamata startUploading tre volte se continua a fallire, altrimenti si fermerà al primo successo.

Modifica. Funzioni che hanno altri params può essere semplicemente incorporati in una chiusura:

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

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

Posso chiedere cosa significa "in" qui in "riprova (3, {successo, errore in updateUsername (newUsername, success, failure)}} "? Grazie. – allenlinli

+2

@allenlinli' in' qui rappresenta il separatore di 'Swift' tra gli argomenti di chiusura e il suo corpo – Cristik

2

Qui è una risposta aggiornata per SWIFT 3. Ho anche aggiunto un oggetto generico nel blocco successo se si fa un oggetto dopo la chiamata di rete è completo puoi passarlo fino alla chiusura finale. Ecco la funzione di reset:

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

Ed ecco come si usa se aggiornati un utente e voleva tornare un nuovo oggetto utente con l'informazioni aggiornate:

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

Ciao Justin, è possibile utilizzarlo con questa funzione: func dataTask (con richiesta: URLRequest, completionHandler: @escaping (dati ?, URLResponse ?, errore?) -> vuoto) -> URLSessionDataTask Grazie – lveselovsky