weak / unowned
Swift's weak (weak reference) and unowned (unowned reference) are mechanisms to prevent retain cycles. They do not increment the reference count, so they do not keep an instance alive after it is deallocated.
Syntax
// weak: Optional type. Automatically becomes nil after the instance is deallocated
weak var reference: ClassName?
// unowned: Non-optional type. Accessing it after the instance is deallocated causes a crash
unowned var reference: ClassName
// Closure capture list
{ [weak self] in
self?.method()
}
{ [unowned self] in
self.method()
}
Syntax overview
| Syntax | Description |
|---|---|
| weak var | Weak reference. Automatically becomes nil when the referenced instance is deallocated (Optional type). |
| unowned var/let | Unowned reference. Use when the referenced instance is guaranteed to outlive the current instance (non-optional type). |
| [weak self] | Captures self as a weak reference inside a closure. |
| [unowned self] | Captures self as an unowned reference inside a closure. |
Sample code
class Apartment {
let unit: String
weak var tenant: Resident? // Use weak to break the retain cycle
init(unit: String) { self.unit = unit }
deinit { print("Apartment \(unit) was deallocated") }
}
class Resident {
let name: String
var apartment: Apartment? // Strong reference (only one side needs to be weak)
init(name: String) { self.name = name }
deinit { print("\(name) was deallocated") }
}
// Resolve the retain cycle with weak
var apt: Apartment? = Apartment(unit: "101")
var bob: Resident? = Resident(name: "Bob")
apt!.tenant = bob
bob!.apartment = apt
apt = nil // Apartment is deallocated (Bob's weak reference becomes nil)
bob = nil // Resident is also deallocated
print("--- Both instances were deallocated ---")
// unowned: use when the referenced instance always exists
class CreditCard {
let number: String
unowned let owner: Customer // Customer is always guaranteed to exist
init(number: String, owner: Customer) {
self.number = number
self.owner = owner
}
deinit { print("Card \(number) was deallocated") }
}
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
deinit { print("\(name) was deallocated") }
}
var alice: Customer? = Customer(name: "Alice")
alice!.card = CreditCard(number: "1234-5678", owner: alice!)
alice = nil // Both Customer and CreditCard are deallocated
// Using [weak self] in a closure
class ViewController {
var name = "Screen A"
func doAsyncWork() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return } // nil check
print("\(self.name) finished processing")
}
}
}
Notes
When a retain cycle occurs, make one of the references weak or unowned. Use the safer weak when the lifecycle of the referenced instance is uncertain, and unowned when the referenced instance is guaranteed to outlive the current one.
If a closure captures self with a strong reference, a retain cycle may occur. In asynchronous closures, it is common practice to use [weak self] and unwrap with guard let self = self else { return }. Accessing a deallocated instance through an unowned reference causes a runtime crash. Use weak if the lifecycle of the referenced instance is not certain.
For more on how ARC works, see ARC / Strong References / Retain Cycles.
If you find any errors or copyright issues, please contact us.