Swift: The rules of being weak and unowned in closures and capture lists (Xcode 6 Beta 7)


Following earlier posts on the weakunowned and lazy keywords, I consider here their use with closures.

Why worry about using weak and unowned in closures?

The first thing to do is to explain why we need to use weak and unowned in closures. And the best people to do that are the people writing the Swift documentation, so let's start with why we need to worry about this in our code:
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. (Apple)

How to solve the problem with capture lists

It can feel like a daunting level of responsibility to not create a strong reference cycle inside a closure, but if we take our time to understand the capture list then our anxieties can be alleviated: 
A closure expression can explicitly specify the values that it captures from the surrounding scope using a capture list. A capture list is written as a comma separated list surrounded by square brackets, before the list of parameters. If you use a capture list, you must also use the in keyword, even if you omit the parameter names, parameter types, and return type.

Each entry in the capture list can be marked as weak or unowned to capture a weak or unowned reference to the value.

myFunction { print(self.title) }                    // strong capture
myFunction { [weak self] in print(self!.title) }    // weak capture
myFunction { [unowned self] in print(self.title) }  // unowned capture

You can also bind an arbitrary expression to a named value in the capture list. The expression is evaluated when the closure is formed, and captured with the specified strength. For example:

// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }" (Apple)

Rules of using weak and unowned in closures

First, it is important to make clear that this whole issue only concerns closures where we are assigning "a closure to a property of a class instance". Keep this in mind with each rule.

The rules:
  1. use weak capture if the class instance or property is an optional
  2. use unowned if the class instance or property is non-optional and can never be set to nil
  3. "you must ... use the in keyword, even if you omit the parameter names, parameter types, and return type"
Note: in each of the examples below the closures are lazy properties, because otherwise they would be unable to access instance variables, since these are not available until after the initialization of a class.

Explanations and code examples

A strong capture looks like this:
class Parent {
    var title = "Dad"
    lazy var parentOf:(String)->String = {
    (childname:String) in return childname+"'s "+self.title
    } // DON'T DO THIS UNLESS YOU WANT THE CLOSURE TO KEEP THE INSTANCE ALIVE!!!
 }
And we add a "capture list" to fix it:
class Parent {
    var title = "Dad"
    lazy var parentOf:(String)->String = {
    [unowned self] (childname:String) in return childname+"'s "+self.title
    } // OK
 }
Note: The capture list is the [unowned self] part.

Difference between unowned and weak

Even if the title property was optional, we would still use unowned
class Parent {
    var title:String? = "Dad"
    lazy var parentOf:(String)->String = {
    [unowned self](childname:String) in return childname+"'s "+self.title!
    }
}
because it is the String (in this case) that is optional not the class instance. However, let's suppose we have a child class and inside this class we have an optional that is of type Parent:
class Child {
    var parent:Parent?
    init (parent:Parent) {
        self.parent = parent
    }
    lazy var myParent:()->() = { [weak parent = self.parent] in print(parent!.title) }
}
Now we use weak because the class instance is an optional. We're also using the syntax that goes beyond simply referring to self but allows us to specify a property. Notice how in the body of the closure we reference self.parent now as simply parent. (Tip: Try replacing weak with unowned and you'll see a compiler error.)

Using unowned and weak together

Let's suppose we add a grandparent into the mix but that the grandparent is not optional. We can then simply add this grandparent property to our capture list (but this time we use unowned because the grandparent is an non-optional instance):
class Child {
    var parent:Parent?
    var grandparent:GrandParent
    init (parent:Parent, grandparent:GrandParent) {
        self.parent = parent
        self.grandparent = grandparent
    }
    lazy var myParent:()->() = { [weak parent = self.parent, unowned grandparent = self.grandparent] in print("\(parent!.title) is \(grandparent.title)'s son"); }
}
And for completeness, here's the GrandParent class:
class GrandParent {
    var title:String = "Gramps"
}
And here's how I'm calling it in a very basic way:
let kid = Child(parent: Parent(), grandparent:GrandParent())
kid.myParent()

Conclusion

There's a lot to take in here and trying to condense it is a challenge. To understand more fully closures and strong capture, I would recommend you read about Closures, Expressions and Automatic Reference Counting in the Apple documentation. (Note: the compiler is of little guidance in this area, so it's largely up to you to make yourself aware of the requirements.)

Endorse on Coderwall

Comments