Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding swift Alamofire completionHandler

I have these two methods in my API class to get data from an API:

func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
        makeAuthenticateUserCall(completionHandler)
    }

    func makeAuthenticateUserCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
        Alamofire.request(.GET, loginUrlString)
            .authenticate(user: "a", password: "b")
            .responseString { request, response, responseString, responseError in
                completionHandler(responseObject: responseString as String!, error: responseError)
        }
    }

Then in another class i use the following code to access the data:

API().authenticateUser{ (responseObject, error) in
    println(responseObject)
}

The code is working but i don't understand it completely.

  1. func authenticateUser has the parameter completionHandler: (responseObject: String?, error: NSError?) -> (), is this a reference to the completionHandler method? or is it an object? whats the purpose of -> ()?
  2. When i call the authenticateUser func, how do i actually access the response? There is no return in any of my api funcs, the funcname{(parameter, parameter) in .. } syntax seems really strange.
like image 398
Lord Vermillion Avatar asked Sep 03 '15 09:09

Lord Vermillion


People also ask

What is Alamofire in Swift?

Alamofire is a networking library written in Swift. You use it to make HTTP(S) requests on iOS, macOS and other Apple platforms. For example, to post data to a web-based REST API or to download an image from a webserver. Alamofire has a convenient API built on top of URLSession (“URL Loading System”).

Why do we use Alamofire?

Advantages of Using AlamofireUsing Alamofire will give a cleaner project. API call interactions (POST/GET/PUT/etc.) will be easier and more understable. Alamofire simplifies a number of common networking tasks that makes development faster and easier.

Is Alamofire an asynchronous?

Networking in Alamofire is done asynchronously. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are very good reasons for doing it this way. None of the response handlers perform any validation of the HTTPURLResponse it gets back from the server.


1 Answers

completionHandler is a closure parameter. As Swift documentation says:

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.

So, what a closure is used for is to add some functionality of your own that you want to add to the execution of your function.

In your case, you call authenticateUser and you pass a closure that receives (responseObject, error) and executes println(responseObject). authenticateUser() receives your closure under the completionHandler parameter and it then calls makeAuthenticateUserCall() passing your completionHandler closure to it.

Then again, looking at the definition you can see func makeAuthenticateUserCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) that means that like authenticateUser() makeAuthenticateUserCall() is a function that receives a closure as a parameter, under the name of completionHandler. makeAuthenticateUserCall() makes a network request using AlamoFire and you capture the response under a closure again that you pass as parameter of the responseString() method. So you have:

//here you call authenticateUser with a closure that prints responseObject
API().authenticateUser{ (responseObject, error) in
    println(responseObject)
}

Then:

//authenticateUser receives your closure as a parameter
func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
    //it passes your closure to makeAuthenticateUserCall
    makeAuthenticateUserCall(completionHandler)
}

//makeAuthenticateUserCall receives your closure
func makeAuthenticateUserCall(completionHandler: (responseObject: String?, 
error: NSError?) -> ()) {
    Alamofire.request(.GET, loginUrlString)
        .authenticate(user: "a", password: "b")
        //here you pass a new closure to the responseString method
        .responseString { request, response, responseString, responseError in
            //in this closure body you call your completionHandler closure with the 
            //parameters passed by responseString and your code gets executed 
            //(that in your case just prints the responseObject)
            completionHandler(responseObject: responseString as String!, error: responseError)
    }
}

For more information read the documentation: Swift Closures

like image 152
bitsoverflow Avatar answered Oct 17 '22 19:10

bitsoverflow