Is there a way to do Alamofire requests with retries

I've had the same problem, and I got the requests to be retried using the RequestRetrier, should method and request.retryCount. Something like it:

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

Alamofire 4.0 has a RequestRetrier protocol you can use.

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

Example:

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
        }

        // Or do something with the retryCount
        // i.e. completion(request.retryCount <= 10, 1.0)
    }
}

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

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

One of the bits of syntactic sugar you get with Swift is you can use this:

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

Like this:

updateEvents(someNormalParam: false) {...}

Note the block is outside the () of the updateEvents function, contrary to where you'd normally expect it. It works only if the block is the last thing in the declaration of the function.

That means if you happen to have a block such as your Alamofire request, you can effectively wrap it with your retry functionality. One slightly complicating issue is you want to call a block within the block. Not a big deal:

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

And you use it like so:

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

Meaning all you have to do is find your Alamofire calls and wrap them in { } and put retryWrapper() before. The retry logic itself is only there once.