Blog / August 12, 2023 / 3 mins read / By Mahi Garg

Weak vs Unowned References in Swift

Memory management is a vital consideration when developing applications, and Swift provides developers with different reference types to manage memory effectively. Two of these reference types, weak and unowned, are essential in preventing memory leaks and managing object lifetimes. In this blog, we’ll explore the differences between weak and unowned references through examples, helping you understand when to use each type.

Weak References

Weak references are used to avoid strong reference cycles, which can lead to memory leaks. A strong reference cycle occurs when two or more objects reference each other, creating a loop that prevents them from being deallocated. To break this cycle, weak references are employed. A weak reference doesn’t increase the reference count of an object, and when the object it references is deallocated, the weak reference automatically becomes nil.

Here’s an example demonstrating the usage of weak references:

class Car {
    let model: String
    weak var owner: Person?
    
    init(model: String) {
        self.model = model
        print("Car \(model) is initialized.")
    }
    
    deinit {
        print("Car \(model) is deallocated.")
    }
}

class Person {
    let name: String
    var car: Car?
    
    init(name: String) {
        self.name = name
        print("Person \(name) is initialized.")
    }
    
    deinit {
        print("Person \(name) is deallocated.")
    }
}

var alice: Person?
var herCar: Car?

alice = Person(name: "Alice")
herCar = Car(model: "Toyota Corolla")

alice?.car = herCar
herCar?.owner = alice

alice = nil // Person Alice is deallocated, car.owner becomes nil
herCar = nil // Car Toyota Corolla is deallocated

In this example, the weak reference owner in the Car class prevents a strong reference cycle between alice and herCar. When alice is deallocated, the weak reference owner becomes automatically nil.

Unowned References

Unowned references are also used to break strong reference cycles, but unlike weak references, they assume that the referenced object will never be nil during the lifetime of the reference. If you access an unowned reference after the referenced object has been deallocated, a runtime error occurs. This makes unowned references suitable when the referenced object’s existence is guaranteed.

Here’s an example illustrating the usage of unowned references:

class Library {
    let name: String
    unowned let librarian: Person
    
    init(name: String, librarian: Person) {
        self.name = name
        self.librarian = librarian
        print("Library \(name) is initialized.")
    }
    
    deinit {
        print("Library \(name) is deallocated.")
    }
}

var librarian: Person?
var library: Library?

librarian = Person(name: "John")
library = Library(name: "Swiftville Library", librarian: librarian!)

librarian = nil // Person John is deallocated
// Accessing library.librarian now would lead to a runtime error
library = nil // Library Swiftville Library is deallocated

In this example, the unowned reference librarian in the Library class assumes that the referenced librarian will never be nil as long as the library instance exists.

Weak vs Unowned Rerference

Here’s a summary of the key differences between weak and unowned references:

Weak References:
  • Automatically become nil when the referenced object is deallocated.
  • Used to prevent strong reference cycles and memory leaks.
  • Ideal when the referenced object’s existence is uncertain or temporary.
Unowned References:
  • Assumes that the referenced object will never be nil.
  • Accessing an unowned reference after the referenced object is deallocated results in a runtime error.
  • Suitable when the referenced object’s existence is guaranteed.

Conclusion

In Swift, choosing between weak and unowned references depends on the object’s lifecycle and the relationships between objects. Weak references are used to break strong reference cycles and automatically become nil when the referenced object is deallocated. Unowned references assume the referenced object’s existence and lead to runtime errors if accessed after deallocation. By understanding the distinctions between these two reference types, you can make informed decisions about which one to use in your code, ensuring effective memory management in your Swift applications. Happy coding!

Comments