2

I have a number of requests witch I would like to call one after another without having nested spaghetti code.

I tried it already with a serial dispatch queue

let queue = dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL)

Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
            print(1)
        }

Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
            print(2)
        }

Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
            print(3)
        }

But unfortunately that does not work. The output of this can be 1,3,2 or 3,1,2 or any other combination.

What would be the best approach to get the output 1,2,3 so one after the other.

Eike
  • 2,311
  • 20
  • 31

3 Answers3

4

Ok I ended up writing my own implementation.

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

Eike
  • 2,311
  • 20
  • 31
0

I'm using Artman's Signals to notify my app once a result is returned, after which a queue elsewhere can call it's next request:

Alamofire.request( httpMethod, url, parameters: params ).responseJSON
{
    ( response: Response< AnyObject, NSError > ) in

    self._signals.dispatchSignalFor( Key: url, data: response.result )
}

More details here.

Joseph Beuys' Mum
  • 2,395
  • 2
  • 24
  • 50
-1

One solution is to call your second request in the first one's callback :

Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
            print(1)
            Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
                 print(2)
                 Alamofire.request(Router.Countries).responseString { (response:Response<String, NSError>) in
                      print(3)
                 }
            }
        }
Damien
  • 3,322
  • 3
  • 19
  • 29