Jonnny
Jonnny

Reputation: 5039

Explain Swift Closure syntax

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

Answers (1)

Stefan Arambasich
Stefan Arambasich

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

Related Questions