iOS Interview - Unowned referencing in Swift

May 29, 20244 min read#swift, #ios, #interview

I have got an interview question about unowned recently. While I can answer it correctly, I was struggling a bit when the interviewer asked me examples when I should use unowned, because I’d rather answer: NEVER 😁. I rarely use unowned in my projects, but it’s worth it to understand why the keyword exists and when to use it.

What is unowned?

The unowned keyword is used to define a weak reference to an object in Swift. Unlike a strong reference, which keeps an object alive as long as there is at least one reference to it, an unowned reference does not increase the retain count of the object it refers to. This means that an unowned reference does not prevent the referenced object from being deallocated.

When you declare a property as unowned, you are essentially telling the compiler that you are certain that the referenced object will not be deallocated before the referencing object. If you try to access an unowned reference after the referenced object has been deallocated, your app will crash with a fatal error.

Generally, unowned referencing is faster than weak referencing because the compiler doesn’t need to add extract code for ARC, and the apps don’t need to execute those extra code in runtime.

When to use unowned references?

Breaking Retain Cycles:

One common scenario where unowned is used is to break retain cycles between objects. A retain cycle occurs when two or more objects hold strong references to each other, preventing them from being deallocated even when they are no longer needed. By using unowned, you can break the retain cycle and allow the objects to be deallocated properly.

Example:

class Person {
    var name: String
    var car: Car?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

class Car {
    var model: String
    unowned var owner: Person

    init(model: String, owner: Person) {
        self.model = model
        self.owner = owner
    }

    deinit {
        print("Car \(model) is being deinitialized")
    }
}

In this example, a Person can own a Car, and a Car has an unowned reference to its owner. This prevents a retain cycle between the Person and Car instances.

Parent-Child Relationships:

Another situation where unowned is applicable is when you have a parent-child relationship between objects, and you are certain that the parent object will always outlive the child object.

Example:

class Parent {
    var child: Child?

    deinit {
        print("Parent is being deinitialized")
    }
}

class Child {
    unowned var parent: Parent

    init(parent: Parent) {
        self.parent = parent
    }

    deinit {
        print("Child is being deinitialized")
    }
}

In this case, a Child object always has a parent, and the parent property is declared as unowned because the Parent object is expected to outlive the Child object.

Important Considerations

  • Use unowned only when you are absolutely sure that the referenced object will not be deallocated before the referencing object. If you have any doubts, consider using weak instead.
  • Accessing an unowned reference after the referenced object has been deallocated will result in a runtime crash. Make sure to handle the lifecycle of objects correctly.
  • If the referenced object can be nil at some point, use weak instead of unowned to avoid crashes.

Conclusion

The unowned keyword in Swift is a powerful tool for managing object relationships and preventing retain cycles. By using unowned, you can define weak references to objects and ensure proper memory management. However, it’s important to use unowned carefully and only when you are certain about the lifecycle of the referenced objects. Understanding when and how to use unowned can help you write more efficient and robust Swift code.

Quick Drop logo

Profile picture

Personal blog by An Tran. I'm focusing on creating useful apps.
#Swift #Kotlin #Mobile #MachineLearning #Minimalist


© An Tran - 2024