21

It is my understanding that by default, Alamofire requests run in a background thread.

When I tried running this code:

let productsEndPoint: String = "http://api.test.com/Products?username=testuser"

        Alamofire.request(productsEndPoint, method: .get)
            .responseJSON { response in
                // check for errors
                guard response.result.error == nil else {
                    // got an error in getting the data, need to handle it
                    print("Inside error guard")
                    print(response.result.error!)
                    return
                }

                // make sure we got some JSON since that's what we expect
                guard let json = response.result.value as? [String: Any] else {
                    print("didn't get products as JSON from API")
                    print("Error: \(response.result.error)")
                    return
                }

                // get and print the title
                guard let products = json["products"] as? [[String: Any]] else {
                    print("Could not get products from JSON")
                    return
                }
                print(products)

        }

The UI was unresponsive until all the items from the network call have finished printing; so I tried using GCD with Alamofire:

let queue = DispatchQueue(label: "com.test.api", qos: .background, attributes: .concurrent)

    queue.async {

        let productsEndPoint: String = "http://api.test.com/Products?username=testuser"

        Alamofire.request(productsEndPoint, method: .get)
            .responseJSON { response in
                // check for errors
                guard response.result.error == nil else {
                    // got an error in getting the data, need to handle it
                    print("Inside error guard")
                    print(response.result.error!)
                    return
                }

                // make sure we got some JSON since that's what we expect
                guard let json = response.result.value as? [String: Any] else {
                    print("didn't get products as JSON from API")
                    print("Error: \(response.result.error)")
                    return
                }

                // get and print the title
                guard let products = json["products"] as? [[String: Any]] else {
                    print("Could not get products from JSON")
                    return
                }
                print(products)

        }
    }

and the UI is still unresponsive as it was before.

Am I doing anything wrong here, or does the fault lie with Alamofire?

thetipsyhacker
  • 1,402
  • 4
  • 18
  • 39

1 Answers1

34

I was wrong about Alamofire running on a background thread by default. It actually runs on the main queue by default. I've opened an issue on Alamofire's Github page and it's been solved here: https://github.com/Alamofire/Alamofire/issues/1922

The correct way to solve my problem was to specify what kind of queue I want my request to be run on using the "queue" parameter on the .responseJSON method (

.responseJSON(queue: queue) { response in
...
}

)

This is the entire, corrected version of my code:

let productsEndPoint: String = "http://api.test.com/Products?username=testuser"

    let queue = DispatchQueue(label: "com.test.api", qos: .background, attributes: .concurrent)

    Alamofire.request(productsEndPoint, method: .get)
        .responseJSON(queue: queue) { response in
            // check for errors
            guard response.result.error == nil else {
                // got an error in getting the data, need to handle it
                print("Inside error guard")
                print(response.result.error!)
                return
            }

            // make sure we got some JSON since that's what we expect
            guard let json = response.result.value as? [String: Any] else {
                print("didn't get products as JSON from API")
                print("Error: \(response.result.error)")
                return
            }

            // get and print the title
            guard let products = json["products"] as? [[String: Any]] else {
                print("Could not get products from JSON")
                return
            }
            print(products)
     }
thetipsyhacker
  • 1,402
  • 4
  • 18
  • 39
  • 15
    I think Alamofire request runs by default on a background thread, and the response handler is run on the main thread.. Be aware because now it seems you're running your response handler on a background thread (and if you're making any changes to the UI you must switch to the main thread) – Fidel López Apr 12 '17 at 17:26
  • @FidelEduardoLópez thats right but what if we want to reload every time on response .. sometimes it shows index out of bound? – Bhavin Bhadani Jan 09 '18 at 08:24
  • This syntax also works with `AlamofireImage`. Thank you, Fidel, for clarifying re: the response handler. – Adrian Jun 17 '18 at 23:31
  • 1
    The request actually run in background DispatchQueue. I found it in [source code](https://github.com/Alamofire/Alamofire/blob/master/Source/Session.swift#L64). – Frank Cheng Jun 13 '19 at 23:05