AlamoFire GET api request not working as expected

One way to handle this is to pass a closure (I usually call it a completionHandler) to your siteInfo function and call that inside Alamofire.request‘s closure:

func siteInfo(completionHandler: (String?, NSError?) -> ()) -> () {
    Alamofire.request(.GET, MY_API_END_POINT).responseJSON {
        (request, response, JSON, error) in

        let info = JSON as? NSDictionary // info will be nil if it's not an NSDictionary
        let str = info?["access_key"] as? String // str will be nil if info is nil or the value for "access_key" is not a String

        completionHandler(str, error)
    }
}

Then call it like this (don’t forget error handling):

siteInfo { (str, error) in
    if str != nil {
        // Use str value
    } else {
        // Handle error / nil value
    }
}

In the comments you asked:

So how would you save the info you collect from the get request if you
can only do stuff inside the closure and not effect objects outside of
the closure? Also, how to keep track to know when the request has
finished?

You can save the result of the get request to an instance variable in your class from inside the closure; there’s nothing about the closure stopping you from doing that. What you do from there really depends on, well, what you want to do with that data.

How about an example?

Since it looks like you’re getting an access key form that get request, maybe you need that for future requests made in other functions.

In that case, you can do something like this:

Note: Asynchronous programming is a huge topic; way too much to cover here. This is just one example of how you might handle the data you get back from your asynchronous request.

public class Site {
    private var _accessKey: String?

    private func getAccessKey(completionHandler: (String?, NSError?) -> ()) -> () {

        // If we already have an access key, call the completion handler with it immediately
        if let accessKey = self._accessKey {
            completionHandler(accessKey, nil)
        } else { // Otherwise request one
            Alamofire.request(.GET, MY_API_END_POINT).responseJSON {
                (request, response, JSON, error) in

                let info = JSON as? NSDictionary // info will be nil if it's not an NSDictionary
                let accessKey = info?["access_key"] as? String // accessKey will be nil if info is nil or the value for "access_key" is not a String

                self._accessKey = accessKey
                completionHandler(accessKey, error)
            }
        }
    }

    public func somethingNeedingAccessKey() {
        getAccessKey { (accessKey, error) in
            if accessKey != nil {
                // Use accessKey however you'd like here
                println(accessKey)
            } else {
                // Handle error / nil accessKey here
            }
        }
    }
}

With that setup, calling somethingNeedingAccessKey() the first time will trigger a request to get the access key. Any calls to somethingNeedingAccessKey() after that will use the value already stored in self._accessKey. If you do the rest of somethingNeedingAccessKey‘s work inside the closure being passed to getAccessKey, you can be sure that your accessKey will always be valid. If you need another function that needs accessKey, just write it the same way somethingNeedingAccessKey is written.

public func somethingElse() {
    getAccessKey { (accessKey, error) in
        if accessKey != nil {
            // Do something else with accessKey
        } else {
            // Handle nil accessKey / error here
        }
    }
}

Leave a Comment