Swift Strong, Weak, and Unowned References Example

1. Introduction

In Swift, memory management is handled automatically through Automatic Reference Counting (ARC). While ARC takes care of most of the memory management for us, it's crucial to understand how references work to avoid potential memory leaks. In this post, we'll examine the differences between strong, weak, and unowned references.

2. Source Code Example

class ObjectA {
    var objectB: ObjectB?
    init() {
        print("ObjectA initialized")
    }
    deinit {
        print("ObjectA deinitialized")
    }
}

class ObjectB {
    // Change between strong (default), weak, and unowned
    var objectA: ObjectA?
    init() {
        print("ObjectB initialized")
    }
    deinit {
        print("ObjectB deinitialized")
    }
}

func createObjects() {
    let a = ObjectA()
    let b = ObjectB()

    a.objectB = b
    b.objectA = a
}

createObjects()

Output:

ObjectA initialized
ObjectB initialized
// Possible output: ObjectB deinitialized
// Possible output: ObjectA deinitialized

3. Step By Step Explanation

1. Object Initialization and Deinitialization:

- We have two classes, ObjectA and ObjectB. Both classes have an optional property pointing to an instance of the other class.

- Each class prints a message during its initialization (init) and deinitialization (deinit).

2. Function to Create Instances:

- The createObjects function creates instances of both ObjectA and ObjectB and then sets the properties so that each object has a reference to the other.

3. The Issue of Strong Reference Cycles:

- By default, references in Swift are "strong". This means that as long as there's a reference to an object, that object will stay in memory.

- If both ObjectA and ObjectB have strong references to each other, they create a "strong reference cycle", which means neither object can be deallocated.

4. Breaking the Strong Reference Cycle with weak or unowned:

- To prevent memory leaks from strong reference cycles, you can use either weak or unowned for one of the references. This will ensure that one of the objects doesn't keep a strong hold on the other, allowing them to be deallocated.

- Update the property declaration in ObjectB to experiment with this:- For a weak reference: weak var objectA: ObjectA?- For an unowned reference: unowned var objectA: ObjectA

5. Difference Between weak and unowned:

- weak: This reference doesn't keep the object it points to strongly in memory. It’s always optional and will be set to nil automatically by ARC when the instance it refers to is deallocated.

- unowned: This is similar to weak but it's non-optional. It doesn't keep the instance in memory, but unlike weak, it can lead to runtime crashes if accessed after the instance it refers to has been deallocated. To fully understand and experiment with this example, change the reference from strong (default) to either weak or unowned in the ObjectB class and observe the behavior. 

In summary, understanding the differences between strong, weak, and unowned references is crucial in Swift to ensure efficient memory management and avoid potential memory leaks.


Comments