This question is largely based on this one:
Link
The main difference being that I want to pass in arguments to the closure as well. Say I have something like this:
func someFunctionThatTakesAClosure(completionClosure: (venues: Dictionary<String, AnyObject>, error: NSError) -> ()) {
// function body goes here
var error: NSError?
let responseDictionary: Dictionary<String, AnyObject> = ["test" : "test2"]
completionClosure(venues: responseDictionary, error: error!)
}
No error here. But when I call this function in my main view controller I have tried several ways but all of the result in different errors:
venueService.someFunctionThatTakesAClosure(completionClosure(venues: Dictionary<String, AnyObject>, error: NSError){
})
or like this:
venueService.someFunctionThatTakesAClosure((venues: Dictionary<String, AnyObject>, error: NSError){
})
or even like this:
venueService.someFunctionThatTakesAClosure(completionClosure: (venues: Dictionary<String, AnyObject>, error: NSError) -> (){
});
I'm probably just way tired, but any help would be greatly appreciated!
venueService.someFunctionThatTakesAClosure({
venues, error in
// do stuff
})
you can optionally specify the types (but since the compiler knows what types the closure is supposed to provide, you don't strictly have to:
venueService.someFunctionThatTakesAClosure({
(venues: Dictionary<String, AnyObject>, error: NSError) -> () in
// do stuff
})
But I see another issue in your calling code:
completionClosure(venues: responseDictionary, error: error!)
// No Bueno. What if there's no error? ^^^^^^
You shouldn't force unwrap the error since it's entirely possible that it's still nil. Force unwrapping nil will cause an error. So you want this:
completionClosure(venues: responseDictionary, error: error)
AND you want to change your closure to take an optional error. In total:
func someFunctionThatTakesAClosure(completionClosure: (venues: Dictionary<String, AnyObject>, error: NSError?) -> ()) {
…
completionClosure(venues: responseDictionary, error: error)
}
// when calling:
venueService.someFunctionThatTakesAClosure({
(venues: Dictionary<String, AnyObject>, error: NSError?) -> () in
// do stuff
})
If you'd like to pass additional arguments, keep in mind swift is optimized for closures to be passed as the last argument (and it's a widely followed convention in objective-c APIs):
// in venueService:
func someArgAndClosureFunction(arg1: String, arg2: Int,
completionClosure: (venues: Dictionary<String, AnyObject>, error: NSError?) -> ()) {
// do stuff
}
// When calling:
venueService.someArgAndClosureFunction("string arg 1", arg2: 10) {
(venues: Dictionary<String, AnyObject>, error: NSError?) -> () in
// do stuff
}
In this example I've used the trailing closure syntax which allows you pass the closure outside the function call parens (but it is still passed as the last argument).
As your error is optional, I would make it an optional argument of the passed function:
func someFunctionThatTakesAClosure(completionClosure: (venues: Dictionary<String, AnyObject>, error: NSError?) -> ()) {
// function body goes here
var error: NSError? = nil
let responseDictionary: Dictionary<String, AnyObject> = ["test" : "test2"]
completionClosure(venues: responseDictionary, error: error)
}
It can then be invoked, passing a closure as follows:
someFunctionThatTakesAClosure { println($0); println($1) }
Note, the above is one of the shorthand syntax variants for creating closures.
I think you were probably just tired :)
You're saying that the difficulty you are having is in calling the method, right? None of the examples you gave are passing a valid argument, which should be a closure of type:
(Dictionary<String, AnyObject>, NSError) -> ()
So there are a couple of things you could do...
(a) assign a conforming closure to a variable and pass the variable as the argument to the method:
let myClosure: (Dictionary<String, AnyObject>, NSError?) -> () = { venues, error in
for (key, _) in venues {
println(key)
}
}
venueService.someFunctionThatTakesAClosure(myClosure)
(b) pass a trailing closure as the argument to the method call:
venueService.someFunctionThatTakesAClosure {
venues, error in
for (key, _) in venues {
println(key)
}
}
The syntax for passing in parameters to closures revolve around the in
keyword.
Sorry for the link url...but check out http://fuckingclosuresyntax.com/ and notice in the options where in
appears.
see array.sort({ (item1, item2) in return item1 < item2 })
Which takes in item1
and item2
as 2 inputs