Reputation: 5039
I am new to Swift and closures and was after some help regarding exactly what is going on.
Example 1:
func getData(completionHandler: ((NSArray?, NSError?) -> Void)?) -> Void {
So the function getData
, has a completion handler, of which NSArray
+ NSError
are an optional parameters passed to the function? Is the following bit -> Void)?
that the return type is void, i.e that nothing is set to be returned and the whole closure is optional?
I then wasn't sure what the following -> Void meant
in this case?
Example 2:
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
... do something
}
In this case the completionHandler
data, response and error are assigned within the block to the constant task
. Is that correct? I am unsure about the -> Void in
in relation to error
particularly the additional in
?
I have spent a while looking around at various pieces of code and even writing some myself to get used to the syntax, but it is pretty easy to get confused as I'm finding out http://fuckingclosuresyntax.com/
Upvotes: 2
Views: 584
Reputation: 2361
You are correct about the method signature. -> Void)?
means passing in that completion handler to begin with is optional. It's worth nothing that Void
is indicating that the block should not return a value for its caller to use. The completion handler type there is a closure (anonymous function) type that takes exactly 2 arguments: one of an optional NSArray
type and one of an optional NSError
type (so either/both of those might be nil). It returns nothing to the caller.
In your second example, you are actually creating a completion handler to pass into the dataTaskWithURL
method, with data, response, error
as parameters (more on syntax in a bit). The -> Void
is same as before, an indication that your block returns nothing, despite it being next to the error
. The in
is simply used as a delimiter for the compiler to separate a closure's arguments from its body. This syntax is even shorthanded a little bit. I always generally use parentheses around block arguments, but I suppose that's up to personal style/taste/whatever. So your completionHandler
definition could also look like:
{ (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in // code, end with a }
Now it becomes a bit more clear what's going on. Swift does a lot of inference and allows you to write nice and compactly but it can hide some meaning if you're unfamiliar with the code. This is defining a closure that accepts 3 implicitly unwrapped optionals as parameters: one of an NSData!
type, one of NSURLResponse!
, and one of NSError!
. It returns nothing (-> Void
). The body of the closure, i.e., whatever stuff you want to do, goes after the in
until the next }
. Because the method defines exactly what types are going to get passed into the block, in the implementation, the parameters can simply infer their types by leaving off the type annotation, thus going from data: NSData!
to just data
. Also in Swift, it is valid to leave out the parentheses around the closure arguments, leaving us with that original line of code.
Upvotes: 4