Resolving strong reference cycles between class instances
Swift provides two ways to resolve strong reference cycles when you work with properties of class type: weak references and unowned references.Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle.
Use a weak reference when the other instance has a shorter lifetime. In contrast, use an unowned reference when the other instance has the same lifetime or a longer lifetime.
Weak References
A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. You indicate a weak reference by placing the weak keyword before a property or variable declaration.
ARC automatically sets a weak reference to
nil when the instance that it refers to is deallocated.
NOTE
Property observers aren’t called when ARC sets a weak reference to nil.
Unowned References
You indicate an unowned reference by placing the
unowned keyword before a property or variable declaration.
An unowned reference is expected to always have a value. As a result, ARC never sets an unowned reference’s value to
nil, which means that unowned references are defined using nonoptional types.
IMPORTANT
Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated.
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
NOTE
The examples above show how to use safe unowned references. Swift also provides unsafeunowned references for cases where you need to disable runtime safety checks—for example, for performance reasons. As with all unsafe operations, you take on the responsibility for checking that code for safety.
You indicate an unsafe unowned reference by writing
unowned(unsafe). If you try to access an unsafe unowned reference after the instance that it refers to is deallocated, your program will try to access the memory location where the instance used to be, which is an unsafe operation.Unowned References and Implicitly Unwrapped Optional Properties
The
Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference.
The
Customer and CreditCard example shows a situation where one property that is allowed to be nil and another property that cannot be nil have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.
However, there is a third scenario, in which both properties should always have a value, and neither property should ever be
nil once initialization is complete. In this scenario, it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.
This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle. This section shows you how to set up such a relationship.
The example below defines two classes,
Country and City, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country class has a an implicitly unwrapped optional capitalCity property, and the City class has a unowned country property.Strong Reference Cycles for Closures
A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as
self.someProperty, or because the closure calls a method on the instance, such as self.someMethod(). In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle.
This strong reference cycle occurs because closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure. In essence, it’s the same problem as above.
Swift provides an elegant solution to this problem, known as a closure capture list.
The example below shows how you can create a strong reference cycle when using a closure that references
self. This example defines a class called HTMLElement, which provides a simple model for an individual element within an HTML document:- class HTMLElement {
- let name: String
- let text: String?
- lazy var asHTML: () -> String = {
- if let text = self.text {
- return "<\(self.name)>\(text)</\(self.name)>"
- } else {
- return "<\(self.name) />"
- }
- }
- init(name: String, text: String? = nil) {
- self.name = name
- self.text = text
- }
- deinit {
- print("\(name) is being deinitialized")
- }
- }
Resolving Strong Reference Cycles for Closures
You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A 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. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code.
Place the capture list before a closure’s parameter list and return type if they are provided:
- lazy var someClosure: (Int, String) -> String = {
- [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
- // closure body goes here
- }
If a closure does not specify a parameter list or return type because they can be inferred from context, place the capture list at the very start of the closure, followed by the
in keyword:- lazy var someClosure: () -> String = {
- [unowned self, weak delegate = self.delegate!] in
- // closure body goes here
- }




