Chain multiple Alamofire requests Chain multiple Alamofire requests ios ios

Chain multiple Alamofire requests


Wrapping other asynchronous stuff in promises works like this:

func myThingy() -> Promise<AnyObject> {    return Promise{ fulfill, reject in        Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]).response { (_, _, data, error) in            if error == nil {                fulfill(data)            } else {                reject(error)            }        }    }}

Edit: Nowadays, use: https://github.com/PromiseKit/Alamofire-


I wrote a class which handles a chain of request one by one.

I created a class RequestChain wich takes Alamofire.Request as parameter

class RequestChain {    typealias CompletionHandler = (success:Bool, errorResult:ErrorResult?) -> Void    struct ErrorResult {        let request:Request?        let error:ErrorType?    }    private var requests:[Request] = []    init(requests:[Request]) {        self.requests = requests    }    func start(completionHandler:CompletionHandler) {        if let request = requests.first {            request.response(completionHandler: { (_, _, _, error) in                if error != nil {                    completionHandler(success: false, errorResult: ErrorResult(request: request, error: error))                    return                }                self.requests.removeFirst()                self.start(completionHandler)            })            request.resume()        }else {            completionHandler(success: true, errorResult: nil)            return        }    }}

And I use it like this

let r1 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in    print("1")}let r2 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in    print("2")}let r3 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in    print("3")}let chain = RequestChain(requests: [r1,r2,r3])chain.start { (success, errorResult) in    if success {        print("all have been success")    }else {        print("failed with error \(errorResult?.error) for request \(errorResult?.request)")    }}

Importent is that you are telling the Manager to not execute the request immediately

    let manager = Manager.sharedInstance    manager.startRequestsImmediately = false

Hope it will help someone else

Swift 3.0 Update

class RequestChain {    typealias CompletionHandler = (_ success:Bool, _ errorResult:ErrorResult?) -> Void    struct ErrorResult {        let request:DataRequest?        let error:Error?    }    fileprivate var requests:[DataRequest] = []    init(requests:[DataRequest]) {        self.requests = requests    }    func start(_ completionHandler:@escaping CompletionHandler) {        if let request = requests.first {            request.response(completionHandler: { (response:DefaultDataResponse) in                if let error = response.error {                    completionHandler(false, ErrorResult(request: request, error: error))                    return                }                self.requests.removeFirst()                self.start(completionHandler)            })            request.resume()        }else {            completionHandler(true, nil)            return        }    }}

Usage Example Swift 3

/// set Alamofire default manager to start request immediatly to false        SessionManager.default.startRequestsImmediately = false        let firstRequest = Alamofire.request("https://httpbin.org/get")        let secondRequest = Alamofire.request("https://httpbin.org/get")        let chain = RequestChain(requests: [firstRequest, secondRequest])        chain.start { (done, error) in        }


You have multiple options.


Option 1 - Nesting Calls

func runTieredRequests() {    let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")    putRequest.response { putRequest, putResponse, putData, putError in        let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")        getRequest.response { getRequest, getResponse, getData, getError in            // Process data            // Reload table        }    }}

This is definitely the approach I would recommend. Nesting one call into another is very simple and is pretty easy to follow. It also keeps things simple.


Option 2 - Splitting into Multiple Methods

func runPutRequest() {    let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")    putRequest.response { [weak self] putRequest, putResponse, putData, putError in        if let strongSelf = self {            // Probably store some data            strongSelf.runGetRequest()        }    }}func runGetRequest() {    let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")    getRequest.response { [weak self] getRequest, getResponse, getData, getError in        if let strongSelf = self {            // Probably store more data            strongSelf.processResponse()        }    }}func processResponse() {    // Process that data}func reloadData() {    // Reload that data}

This option is less dense and splits things up into smaller chunks. Depending on your needs and the complexity of your response parsing, this may be a more readable approach.


Option 3 - PromiseKit and Alamofire

Alamofire can handle this pretty easily without having to pull in PromiseKit. If you really want to go this route, you can use the approach provided by @mxcl.