"Weak, Strong, Unowned, Oh My!" - A Guide to References in Swift



I often find myself worrying about retain cycles in my code. I feel like this is a common concern amongst others as well. I don't know about you, but it seems like I am constantly hearing "When am I supposed to use weak? And what the hell is this 'unowned' crap?!" The issue we find is that we know to use strong, weak, and unowned specifiers in our swift code to avoid retain cycles, but we don't quite know which specifier to use. Fortunately, I happen to know what they are AND when to use them! I hope this guide helps you to learn when and where to use them on your own.

Let's get started

ARC

ARC is a compile time feature that is Apple's version of automated memory management. It stands for Automatic Reference Counting. This means that it only frees up memory for objects when there are zero strong references to them.

Strong

Let's start off with what a strong reference is. It's essentially a normal reference (pointer and all), but it's special in it's own right in that it protects the referred object from getting deallocated by ARC by increasing it's retain count by 1. In essence, as long as anything has a strong reference to an object, it will not be deallocated. This is important to remember for later when I explain retain cycles and stuff.

Strong references are used almost everywhere in Swift. In fact, the declaration of a property is strong by default! Generally, we are safe to use strong references when the hierarchy relationships of objects are linear. When a hierarchy of strong references flow from parent to child, then it's always ok to use strong references.

Here is an example of strong references at play.

class Kraken {
    let tentacle = Tentacle() //strong reference to child.
}

class Tentacle { let sucker = Sucker() //strong reference to child }

class Sucker {}

Here we have a linear hierarchy at play. Kraken has a strong reference to a Tentacle instance which has a strong reference to a Sucker instance. The flow goes from Parent (Kraken) all the way down to child (Sucker).

Similarly, in animation blocks, the reference hierarchy is similar as well:

UIView.animate(withDuration: 0.3) {
    self.view.alpha = 0.0
}
Since animateWithDuration is a static method on UIView, the closure here is the parent and self is the child.

What about when a child wants to reference a parent? Here is where we want to use weak and unowned references.

Weak and Unowned References

Weak

A weak reference is just a pointer to an object that doesn't protect the object from being deallocated by ARC. While strong references increase the retain count of an object by 1, weak references do not. In addition, weak references zero out the pointer to your object when it successfully deallocates. This ensures that when you access a weak reference, it will either be a valid object, or nil.

In Swift, all weak references are non-constant Optionals (think var vs. let) because the reference can and will be mutated to nil when there is no longer anything holding a strong reference to it.

For example, this won't compile:

class Kraken {
    //let is a constant! All weak variables MUST be mutable.
    weak let tentacle = Tentacle() 
}
because tentacle is a let constant. Let constants by definition cannot be mutated at runtime. Since weak variables can be nil if nobody holds a strong reference to them, the Swift compiler requires you to have weak variables as vars.

Important places to use weak variables are in cases where you have potential retain cycles. A retain cycle is what happens when two objects both have strong references to each other. If 2 objects have strong references to each other, ARC will not generate the appropriate release message code on each instance since they are keeping each other alive. Here's a neat little image from Apple that nicely illustrates this:

retain-cycle-copy.png

A perfect example of this is with the (fairly new) NSNotification APIs. Take a look at the codes:

class Kraken {
    var notificationObserver: ((Notification) -> Void)?
    init() {
        notificationObserver = NotificationCenter.default.addObserver(forName: "humanEnteredKrakensLair", object: nil, queue: .main) { notification in
            self.eatHuman()
        }
    }

    deinit {            
        NotificationCenter.default.removeObserver(notificationObserver)
    }
}

At this point we have a retain cycle. You see, Closures in swift behave exactly like blocks in Objective-C. If any variable is declared outside of the closure's scope, referencing that variable inside the closure's scope creates another strong reference to that object. The only exceptions to this are variables that use value semantics such as Ints, Strings, Arrays, and Dictionaries in Swift.

Here, NotificationCenter retains a closure that captures self strongly when you call eatHuman(). Best practice says that you clear out notification observers in the deinit function. The problem here is that we don’t clear out the block until deinit, but deinit won’t ever be called by ARC because the closure has a strong reference to the Kraken instance!

Other gotchas where this could happen is in places like NSTimers and NSThread.

The fix is to use a weak reference to self in the closure's capture list. This breaks the strong reference cycle. At this point, our object reference graph will look like this:

Changing self to weak won't increase self 's retain count by 1, therefore allowing to ARC to deallocate it properly at the correct time.

To use weak and unowned variables in a closure, you use the [] in syntax inside of the closure's body. Example:

let closure = { [weak self] in 
    self?.doSomething() //Remember, all weak variables are Optionals!
}

Why is the weak self inside of square brackets? That looks weird! In Swift, we see square brackets and we think Arrays . Well guess what? You can specify multiple capture values in a closure! Example:

//Look at that sweet, sweet Array of capture values.
let closure = { [weak self, unowned krakenInstance] in
    self?.doSomething() //weak variables are Optionals!
    krakenInstance.eatMoreHumans() //unowned variables are not.
}

That looks more like an Array right? So, now you know why capture values are in square brackets. So, now, using what we've learned so far, we can fix the retain cycle in the notification code we posted above by adding [weak self] to the closure's capture list:

NotificationCenter.default.addObserver(forName: "humanEnteredKrakensLair", object: nil, queue: .main) { [weak self] notification in //The retain cycle is fixed by using capture lists!
    self?.eatHuman() //self is now an optional!
}

One other place we need to use weak and unowned variables is when using protocols to employ delegation amongst classes  in Swift, since classes use reference semantics. In Swift, structs and enums can conform to protocols as well, but they use value semantics. If a parent class uses delegation with a child class like so:

class Kraken: LossOfLimbDelegate {
    let tentacle = Tentacle()
    init() {
        tentacle.delegate = self
    }

    func limbHasBeenLost() {
        startCrying()
    }
}

protocol LossOfLimbDelegate {
    func limbHasBeenLost()
}

class Tentacle {
    var delegate: LossOfLimbDelegate?

    func cutOffTentacle() {
        delegate?.limbHasBeenLost()
    }
}

Then we need to use a weak variable.

Here's why:

Tentacle in this case holds a strong reference to Kraken in the form of it's delegate property.

AT THE SAME TIME

Kraken holds a strong reference to Tentacle in it's tentacle property.

To use a weak variable in this scenario, we add a weak specifier to the beginning of the delegate declaration:

weak var delegate: LossOfLimbDelegate?

What's that you say? Doing this won't compile?! Well, the problem is because non class type protocols cannot be marked as weak.

At this point, we have to use a class protocol to mark the delegate property as weak by having our protocol inherit :class.

protocol LossOfLimbDelegate: class { //The protocol now inherits class
    func limbHasBeenLost()
}

When do we not use :class ? Well according to Apple:

Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.

Essentially, if you have a reference hierarchy exactly like the one I showed above, you use :class. In struct and enum situations, there is no need for :class because structs and enums use value semantics while classes use reference semantics.

Unowned

Weak and unowned references behave similarly but are NOT the same. Unowned references, like weak references, do not increase the retain count of the object being referred. However, in Swift, an unowned reference has the added benefit of not being an Optional.  This makes them easier to manage rather than resorting to using optional binding. This is not unlike Implicitly Unwrapped Optionals . In addition, unowned references are non-zeroing. This means that when the object is deallocated, it does not zero out the pointer. This means that use of unowned references can, in some cases, lead to dangling pointers. For you nerds out there that remember the Objective-C days like I do, unowned references map to unsafe_unretained references.

This is where it gets a little confusing. Weak and unowned references both do not increase retain counts. They can both be used to break retain cycles. So when do we use them?! According to Apple's docs:

Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.

Well there you have it: Just like an implicitly unwrapped optional, If you can guarantee that the reference will not be nil at its point of use, use unowned. If not, then you should be using weak.

Here's a good example of a class that creates a retain cycle using a closure where the captured self will not be nil:

class RetainCycle {
    var closure: (() -> Void)!
    var string = "Hello"

    init() {
        closure = {
            self.string = "Hello, World!"
        }
    }
}

//Initialize the class and activate the retain cycle.
let retainCycleInstance = RetainCycle()
retainCycleInstance.closure() //At this point we can guarantee the captured self inside the closure will not be nil. Any further code after this (especially code that alters self's reference) needs to be judged on whether or not unowned still works here.

In this case, the retain cycle comes from the closure capturing self strongly while self has a strong reference to the closure via the closure property. To break this we simply add [unowned self] to the closure assignment:

closure = { [unowned self] in
    self.string = "Hello, World!"
}

In this case, we can assume self will never be nil since we call closure immediately after the initialization of the RetainCycle class.

Apple also says this about unowned references:

Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.

If you know your reference is going to be zeroed out properly and your 2 references are MUTUALLY DEPENDENT on each other (one can't live without the other), then you should prefer unowned over weak, since you aren't going to want to have to deal with the overhead of your program trying to unnecessarily zero your reference pointers.

A really good place to use unowned references is when using self in closure properties that are lazily defined like so:

class Kraken {
    let petName = "Krakey-poo"
    lazy var businessCardName: (Void) -> String = { [unowned self] in
        return "Mr. Kraken AKA " + self.petName
    }
}

We need unowned self here to prevent a retain cycle. Kraken holds on to the businessCardName closure for it's lifetime and the businessCardName closure holds on to the Kraken for it's lifetime. They are mutually dependent, so they will always be deallocated at the same time. Therefore, it satisfies the rules for using unowned!

HOWEVER, this is not to be confused with lazy variables that AREN'T closures such as this:

class Kraken {
    let petName = "Krakey-poo"
    lazy var businessCardName: String = {
        return "Mr. Kraken AKA " + self.petName
    }()
}

Unowned self is not needed since nothing actually retains the closure that's called by the lazy variable. The variable simply assigns itself the result of the closure and deallocates the closure (and decrements the captured self's reference count) immediately after it's first use. Here's a screenshot that proves this! (Screenshot taken shamelessly from Алексей in the comments section!)

Conclusion

Retain cycles suck. But with careful coding and consideration of your reference hierarchy, memory leaks and abandoned memory can be avoided through careful use of weak and unowned. I hope this guide helps you in your endeavors.

Happy coding fellow nerds!