Swift : Converting inline to trailing closures in function - ios

So I have the following function defined:
public typealias RESTClosure = (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void
public func queryAllFlightsWithClosure(completionHandler : RESTClosure) {
// code ....
}
I'm able to call this function as:
func myResponseHandler(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void {
// code ...
}
rest?.queryAllFlightsWithClosure(myResponseHandler)
From my understanding of Swift, however, if the final argument of a function is a closure it can be converted into a trailing closure ... but I've run into some syntax confusion:
Attempt #1
rest?.queryAllFlightsWithClosure() {
println("Called with Closure")
}
Error:
Tuples types '(response: NSURLResponse!, data NSData!, error: NSError!)' and '()' have different number of elements (3 vs. 0)
Attempt #2
rest?.queryAllFlightsWithClosure() (RESTClosure.self) { // Xcode told me to add a .self
//...code
}
Error: Missing argument for parameter #1 in call
I know I'm close ... but anybody can help me here?

Your parameters go inside the closure, and since there's just the one argument, you can even leave out the parentheses:
rest?.queryAllFlightsWithClosure {
(response: NSURLResponse!, data: NSData!, error: NSError!) in
// code ...
}
If you're going to be accessing self or any properties inside the closure, you'll want to include self in a capture list, like this:
rest?.queryAllFlightsWithClosure {
[weak self] (response: NSURLResponse!, data: NSData!, error: NSError!) in
// code ...
// note that self is optional inside this closure b/c of [weak self]
self?.doSomething()
}

Well this seems to compile
rest?.queryAllFlightsWithClosure() { RESTClosure in
// code ...
}

Related

Completion handler in function

I have a function that looks like this, and I have tried to add a completionHandler in the code below:
func getValueFromAPI(completionHandler: (_ result: Bool) -> Void){
apii.getVehicle(id!).done {
(vehicle: Vehicle) -> Void in
print("ggg.state: \(vehicle.state!)")
print("ggg.state: \(vehicle.displayName!)")
apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
let entryBattery = (extendedVehicle.chargeState?.batteryLevel)!
let entryCarState = (extendedVehicle.state)!
print("entryBattery: \(entryBattery)")
print("entryCarState: \(entryCarState)")
completionHandler(true)
}.catch { (error) in
print("ERROOOOR: \(error)")
}
}.catch { error in
print("errorr: \(error)")
}
}
I have already tried to add a complete handler, but I get the following error on these lines:
Line: apii.getVehicle(id!).done {
Error: Escaping closure captures non-escaping parameter 'completionHandler'
Line: apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
Error: Escaping closure captures non-escaping parameter 'completionHandler'
What am I doing wrong here, and how can I fix this?
I am using Swift 5.
You need to declare your completionHandler to be an escaping closure. E.g.:
func getValueFromAPI(completionHandler: #escaping (Bool) -> Void) {
...
}
Note the #escaping qualifier.

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.
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 -> ()?
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.
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

Cannot invoke 'responseArray' with an argument list of type

I'm using Alamofire, with ObjectMapper, things were so smooth before upgrading to Swift 2.0, now,
For the following signature:
public func responseArray<T: Mappable>(completionHandler: ([T]?, ErrorType?) -> Void) -> Self
I'm calling
Alamofire.request(.GET, URL, parameters: nil)
.responseArray { (response: [MyObject]?, error: NSError?) in
}
and getting the following error:
Cannot invoke 'responseArray' with an argument list of type
(([MyObject]?, NSError?) -> ())
Any help will be super appreciated.
try this.
Alamofire.request(.GET, URL, parameters: nil)
.responseArray { (response: [MyObject]?, error) in
//your process
}

Alamofire return string value

i'm trying to write a method to return a json response from an API as a string. This is my code:
func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
makeCall(completionHandler: completionHandler)
}
func makeCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
Alamofire.request(.GET, loginUrlString)
.authenticate(user: "x", password: "y")
.responseString { request, response, responseObject, error in
completionHandler(responseObject: responseObject as? String, error: error)
}
}
I can't compile it, the makeCall call in authenticateUser method says "Extraneous argument label 'completionHandler' in call.
I can't see whats wrong in my code?
Try just calling makeCall(completionHandler).
From the error message, I would guess that that is what it is complaining about. Swift function label use often seems inconsistent and confusing.

How to mock NSURLConnection.sendAsynchronousRequest in unit testing

I have a function in which i am calling a network call as,
func newtorkCall() {
//some other code
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response:
NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if (data != nil) {
//save the data in a variable temp
}
})
}
this is working fine and i am getting the data.
But i want to mock this NSURLConnection.sendAsynchronousRequest in unit testing so that i can hardcode the data and pass it to the variable temp in the source code and test it.
How can I do it?

Resources