I’ve already ranted about how Swift is not the one true gospel (over here), but let me reiterate. Swift has it’s problems. I don’t think it’s perfect. There are some things I like about it.
One of the things that I love about it is lazy properties. A lazy property is one that will be allocated and initialized when it is first used. This technique is used all over the place in iOS, as well as in other languages. Swift has amazing support for lazy properties. But in order to understand them, we must first speak a little about closures. If you already know about closures, you can jump over to this post.
My favorite reference for closure syntax is this article. It’s got some quick and dirty answers for syntactical questions. If you want to go more in depth, go read the language guide, it’s not that hard to read documentation. But in the interest of giving myself a place to look when I forget, here’s some basic closure syntax.
Closure as a Method Parameter
This one’s pretty simple, but I always seem to get it wrong on my first try.
1 2 3 |
func foo(block: (Int, Int) -> (Bool)) { } |
Just remember that the syntax of a closure is
() -> ()
and you should be fine. This should look strikingly similar to how functions are declared.
Defining a Closure
This should be fairly straight forward
1 2 3 |
{ (params) -> returnType in statements } |
Keep in mind that if there is no return, you can either leave the return type off, or use
Void
. Or if you have a single line closure, you don’t need to put the return type at all (or even use the return keyword in the closure.
1 2 3 4 5 6 |
let a = [1, 2, 3] let doubleA = a.map( { (obj) in obj * 2 }) //doubleA = [2, 4, 6] |
You also don’t have to provide names for the parameters and can instead reference them by position ($0, $1…) this is really useful for short closures where the parameters are pretty obvious.
1 2 |
let a = [1, 2, 3] let doubleA = a.map( { $0 * 2 } ) |
Trailing Closures
This one is by far my favorite. If the last parameter of a method is a closure, you can leave it out of the method call, and just provide the closure after the method. For example, this is what GCD might look like without trailing closures
1 2 3 |
dispatch_async(dispatch_get_main_queue(), { //do some work }); |
Notice that the last
)
is after the
}
. It just looks weird. With trailing closures, it would look like this
1 2 3 4 |
dispatch_async(dispatch_get_main_queue()) { //do some work }; |
So the syntax is more of what you might expect to follow a control statement.
The syntax can look even prettier if you have a method with named parameters
1 2 3 4 5 6 7 8 9 10 11 |
//without trailing closure someAsyncMethod(param1, otherParameter: param2, completionHandler: { (results) in //do something }) //with trailing closure someAsyncMethod(param1, otherParameter: param2) { (results) in //do something } |
Here’s a note from the documentation on trailing closures
If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses
()
after the function’s name when you call the function.
This can make
map
a little prettier.
1 2 |
let a = [1, 2, 3] let doubleA = a.map { $0 * 2 } |
Now that we have some syntax under our belt, you’re ready to jump over to this post, to get closer to some awesome things you can do with closures.