问题
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!
回答1:
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).
回答2:
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.
回答3:
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)
}
}
回答4:
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
来源:https://stackoverflow.com/questions/24129112/usage-of-closures-with-multiple-arguments-in-swift