Sobes.tech
Middle

What is unowned in Swift and how is it used?

sobes.tech AI

Answer from AI

Unowned reference (weak indirect ownership) in Swift is used to avoid strong reference cycles (retain cycles), where two objects strongly reference each other, preventing their deallocation from memory.

Features of unowned:

  • Guarantees that the object referenced by the unowned reference always exists at the moment of access.
  • If you try to access an unowned reference after the related object has been deallocated, a runtime crash will occur.
  • Used when the lifecycle of the referencing object is not longer than the lifecycle of the object it references. That is, an unowned reference does not make the object stronger.

Example of usage in capturing closures:

class Customer {
    let name: String
    var card: CreditCard?

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

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

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Unowned reference to Customer

    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }

    deinit {
        print("Card #\(number) is being deinitialized")
    }
}

var john: Customer? // Optional Customer for deallocation
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Setting john to nil will deallocate Customer and Card,
// since there is no strong reference cycle
john = nil 

Another example - using unowned in a closure capture list:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [unowned self] in // Using unowned self
        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")
    }
}

var paragraph: HTMLElement? // Optional HTML element
paragraph = HTMLElement(name: "p", text: "hello world")
print(paragraph!.asHTML())

// Setting paragraph to nil will deallocate HTMLElement, as the closure does not strongly hold it
paragraph = nil

Choosing between unowned and weak depends on whether the reference can be nil during the object's lifetime. If the reference can never become nil before the object is deallocated, use unowned. If it can, use weak.