Closures are “are self-contained blocks of functionality [or chunks of code] that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.” (See my previous article on Blocks in Objective-C for more details). In Swift, functions are actually just a special case of Closures. 

Some closures can be anonymous (without a name), so you can’t just arbitrarily call a closure to be executed.  As far as the reason for using the name “Closure” in Swift, it turns out that the “act of capturing outside values and references to be used inside a closure is called closing, hence the name closure” (Miller, 2016). 

Closures are typically enclosed in curly braces { } and are defined by a function type: 

{() -> () in … return x}

Where -> separates the arguments and the return type, followed by the in keyword which separates the closure header from its body. Then we might return something like x above.

Example Syntax of a Closure Expression (“Closure”)

Screen Shot 2018-02-22 at 12.03.43

So you therefore might see a closure expression like this:

Screen Shot 2018-02-22 at 12.09.49

Swift automatically provides us with shorthand argument names for inline closures, which can be used to refer to the values of the closure’s arguments using the naming convention of $0$1$2 and so on.  For example:

Screen Shot 2018-03-22 at 10.18.32

Trailing Closure Syntax

If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, you can choose to use Swift’s trailing closure syntax instead. A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function (it has to be the last argument). So to say that again another way, when you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.

Screen Shot 2018-03-22 at 10.00.26.png

This attempt at syntactic sugar for closure arguments doesn’t always work out that well though as it can get confusing if your passing more that one closure as an argument. We get the strange syntax of one closure argument being both labeled and inside the () braces but the last one sitting outside in the {} braces, which could prove confusing. So as a point of style my own preference would be to only use trailing closure syntax where we have a single closure as the end argument, otherwise it doesn’t read well and is not consistent. 

Escaping Closures

A closure is said to escape a function when the closure is passed as an argument to a function, but is called/invoked after the function returns. An escaping closure lives outside the function it is passed to, but a non-escaping closure lives within the function it is passed to, and thus it has to execute before the function returns.In Swift 3 or later, when you declare a function that takes a closure as one of its parameters, you write @escaping before the parameter’s type to indicate that the closure should be of the escaping type.

N.B. In Swift 2, a closure would default to escaping unless marked with @noescape, in Swift 3 and later this is inverted with @noescape being the default, and one must now mark a function with the @escaping parameter in order to allow the escaping behavior.

So this is something we typically see in Completion Handlers which in swift might look like this:

Screen Shot 2018-03-22 at 10.09.08

So to explain what’s going on here, we have an escaping closure which we have labeled success, it happens to take a String as an argument and it doesn’t return anything, therefore by using the syntax success(“You won!!\n”) we say that, once this function we’re in completes, we want to trigger the execution of the closure marked with the label success and give it the string (“You won!!\n”) as an argument.

Looking at how our main function get called at line 22, we see that for this String argument, we locally give it the name “x” which allows us to then do something like print(x) to actually then print out the string that got passed back to us from the function when it completed.  Then the second case which we call at line 28 is an example of the same thing for a second closure we pass in called failure.  That is, in this case we’ve got two escaping closures, indeed we could have more if we wanted, but in this case we’ve got one for something we’ve chosen to give the name “failure” as a second closure which may be chosen by our function to be executed on the completion of the function.

 

Optional Closures Always Escaping?

In addition we should note that in Swift … optional closures are always escaping (Ref#: L) apparently because “since the closure is no longer an immediate parameter in this case, it automatically becomes escaping” (Ref#: L).

This apparently means that “@escaping is valid only on closures in function parameter position. The noescape-by-default rule only applies to these closures at function parameter position, otherwise they are escaping. Aggregates, such as enums with associated values (e.g. Optional), tuples, structs, etc., if they have closures, follow the default rules for closures that are not at function parameter position, i.e. they are escaping” (Ref#: M).

 

Retain Cycles in Closures

One potential issue with using closures is the possibility of creating retain cycles: Indeed, as you’ll likely recall, retain cycles tend to happen when you have two objects which each hold strong pointers to one another, either directly so or indirectly, meaning they can’t get deallocated by Automatic Reference Counting (ARC) (generally to solve such cycles one can analyze your app’s object graph and one can use of value types to prevent cycles altogether).

Closures are a Reference Type in Swift, where variable and constants captured by a Swift closure are captured by reference from their enclosing scope (much like __block marked parameters in Objective-C which get captured by reference by Objective-C blocks). The default is for a closure expression to capture stuff from its scope using strong references, however (to avoid retain cycles), we may want to modify our references to a captured values.

To overcome retain cycles in closures we use the reference modifiers of weak or unowned. We want to use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime or in other words when the other instance has a shorter lifetime and thus could be the first to be deallocated. Alternatively we could use the unowned reference if we know that the reference is never going to become nil once it has been initialized.

In order to achieve the above with closures we use a method called Capture Lists which looks like square brackets at the start of a closure (i.e. [weak self]). This Capture List is actually an array of things to be captured and defines the rules to use when capturing one or more reference types within the closure’s body. We also have the option to create new named variables within a Capture List.

So therefore in Swift, we have the option of using a Capture List inside a closure to prevent a retain cycles. Using a capture list means you must also use the in keyword, even when you are omitting the parameter names, parameter types, and return type. Entries in the capture list are initialized when the closure is created, and for each entry a constant is initialized to the value of the constant or variable that has the same name in the closure’s surrounding scope. So therefore the “capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference” (Ref#: J).

Screen Shot 2018-03-22 at 10.13.29.png

Beyond this we might want to actually extend the lifetime of the objects we are using, through a pattern like:

and inside the closure:

For example:

There’s also another similar way of doing this using backticks, such as the following code snippit:

The above pattern will be reminiscent to some of a similar pattern seen with blocks in Objective-C.

If we’re not totally sure whether self will outlive the lifetime of our closure we should typically use [weak self] instead of [unowned self] this is because using [unowned self] could lead the app to crash if self is released before the closure returns. Furthermore, explicitly extending the lifetime of the reference instead of using optional unwrapping is the preferred approach to doing things. The problem with using optional unwrapping inside your closures is that you could end up with something like this happening:

(Ref#: K)

Autoclosures

“An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function” (Ref#: A). So indeed it allows you to pass an expression to a function as an argument. Thus by wrapping the expression in a closure, the function can decide if and when a particular closure get invoked, and then moment the closure is invoked the expression will be evaluated.

screen-shot-2018-02-23-at-02-31-28.png

For more in depth information review the apple documentation on this subject or some of the high quality blog post out there which cover more example then we have covered in today’s post.

 

References

A: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

B: https://github.com/reinder42/SwiftCheatsheet/blob/master/swift-4-cheatsheet.md

C: https://cocoacasts.com/how-to-use-autoclosures-and-autoclosure-in-swift-3

D: https://cocoacasts.com/what-do-escaping-and-noescape-mean-in-swift-3

E: https://grokswift.com/completion-handlers-in-swift/

F: http://www.thomashanning.com/retain-cycles-weak-unowned-swift

G: http://conradstoll.com/blog/2013/1/19/blocks-operations-and-retain-cycles.html

H: https://krakendev.io/blog/weak-and-unowned-references-in-swift

I: https://www.bobthedeveloper.io/blog/swift-capture-list-in-closures

J: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID56

K: https://github.com/raywenderlich/swift-style-guide

L: https://oleb.net/blog/2016/10/optional-non-escaping-closures/

M: https://stackoverflow.com/questions/39618803/swift-3-optional-escaping-closure-parameter?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

 

Updated: Sunday 20th May 2018

Loading

Last modified: June 12, 2018

Author

Comments

Write a Reply or Comment

Your email address will not be published.