2016-05-24 30 views
8

Ho un sacco di posti nel codice in cui vengono gestite richieste/risposte di Alamofire.C'è un modo per fare richieste Alamofire con tentativi

Ciascuna di queste richieste potrebbe non riuscire a causa di alcuni problemi intermittenti (il più comune è la rete instabile).

Vorrei essere in grado di riprovare le richieste 3 volte prima del salvataggio.

Il metodo semplice sarebbe quello di avere una cosa del genere

var errorCount = 0 
func requestType1() { 
    let request = Alamofire.request(...).responseJSON { response in 
     if (isError(response) && errorCount < 3) { 
      errorCount += 1 
      request1() 
     } 
     if (isError(response)) { 
      handleError() 
     } 

     handleSuccess() 
    } 
} 

Tuttavia, non mi piace questo approccio molto per diverse ragioni. Il più ovvio è che avrò bisogno di implementare tale codice per ogni tipo di richiesta (e ne ho qualcosa come 15).

Sono curioso se c'è modo per fare qualcosa di simile (dove i cambiamenti sono minimi e non invadente)

let request = Alamofire.request(..., **3**) 
+0

Potrebbe fare un wrapper che prende la richiesta come un blocco di fine?Quindi, invece di chiamare direttamente la richiesta, hai lo stesso codice di richiesta nel blocco ma chiama il wrapper? Rende più facile cambiare il codice. – Carlos

+0

Carlos. Penso che tu abbia ragione. Ho trascurato questo :). Vuoi scrivere come risposta? –

+0

Certo, dammi un po 'di tempo e lo farò – Carlos

risposta

3

Uno dei pezzi di zucchero sintattico che si ottiene con Swift è è possibile utilizzare questo:

public func updateEvents(someNormalParam: Bool = true, someBlock: (Void->Void)) 

Ti piace questa:

updateEvents(someNormalParam: false) {...} 

Nota il blocco è al di fuori del() del aggiornamento regolare la funzione teEvents, contrariamente a quanto normalmente ti aspetti. Funziona solo se il blocco è l'ultima cosa nella dichiarazione della funzione.

Ciò significa che se si dispone di un blocco come la richiesta Alamofire, è possibile eseguirlo in modo efficace con la funzionalità Riprova. Un problema leggermente complicato è che si desidera chiamare un blocco all'interno del blocco. Non è un grosso problema:

func retryWrapper(alamoBlock: (Void->Request)) { 
    alamoblock().responseJSON() { 
     //Your retry logic here 
    } 
} 

E lo si utilizza in questo modo:

retryWrapper() { 
    Alamofire.request(method, targetUrl, parameters: parameters, encoding: encoding) 
} 

Significato tutto quello che dovete fare è trovare la vostra Alamofire chiama e li avvolgono in {} e mettere retryWrapper() prima. La logica di riprova stessa è solo lì una volta.

+0

Sono poco confuso qui .. cosa rispondiamo aJSON() qui? – Ranjit

+0

Sono un po 'arrugginito ma sembra che il blocco restituisca una richiesta, che ha una funzione che la trasforma in JSON – Carlos

+0

Non possiamo usare requestRetrier? – Ranjit

-3

Bene quello che ho fatto è il seguente, se la richiesta non riesce, invio una notifica non riuscita a chiunque abbia fatto la richiesta. Quindi è responsabile di riprovare la richiesta. Trovato questo per essere molto più facile.

Alamofire.request(.GET, urlString, parameters: params, headers: defaultHeaders) 
     .validate() 
     .responseJSON 
     { 
      response in 

      switch response.result 
      { 
      case .Success: 
       print("Request Successful") 

       let json = JSON(data:response.data!) 

       NSNotificationCenter.defaultCenter().postNotificationName(SUCCESS_NOTIFICATION, object: movieArray) 

      case .Failure(let error): 
       print("Request Failed with error \(error)") 
       NSNotificationCenter.defaultCenter().postNotificationName(FAILURE_NOTIFICATION, object: error) 
      } 
    } 
+2

Non consiglio questo approccio. È saggio essere più giudiziosi nell'uso delle NSNotifications. Se li stai usando, chiediti se non c'è un approccio migliore. Ad esempio, in questo caso sarebbe molto meglio utilizzare le chiusure per effettuare i callback. Utilizzare le chiusure come gestori del completamento è una pratica e un modello standard per questo tipo di cose. –

10

Alamofire 4.0 ha un protocollo RequestRetrier è possibile utilizzare.

https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md#request-retrier

Esempio:

class OAuth2Handler: RequestAdapter, RequestRetrier { 
    public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: RequestRetryCompletion) { 
     if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 { 
      completion(true, 1.0) // retry after 1 second 
     } else { 
      completion(false, 0.0) // don't retry 
     } 
    } 
} 

let sessionManager = SessionManager() 
sessionManager.retrier = OAuth2Handler() 

sessionManager.request(urlString).responseJSON { response in 
    debugPrint(response) 
} 
1

Ho avuto lo stesso problema, ho le chiede di essere processati nuovamente utilizzando il RequestRetrier, should metodo e request.retryCount. Qualcosa di simile: ` // MARK: - RequestRetry

public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) { 
    lock.lock() ; defer { lock.unlock() } 


    if let response = request.task?.response as? HTTPURLResponse{ 
     if response.statusCode == 401 { 
      requestsToRetry.append(completion) 

      getToken { (expires, _) in 
       _ = SessionCountdownToken.sharedInstance.startCount(expirationTime: expires) 
      } 
     } else { 

      if request.retryCount == 3 { completion(false, 0.0); return} 
      completion(true, 1.0) 
      return 
     } 
    } else { 
     completion(false, 0.0) 
    } 
}`