Middle
What types of references exist in Swift?
sobes.tech AI
Answer from AI
In Swift, there are three main types of references:
-
Strong Reference:
- Increases the reference count of an object instance.
- Prevents deallocation of the object as long as at least one strong reference exists.
- Is the default reference type in Swift.
- The main cause of strong reference cycles.
-
Weak Reference:
- Does not increase the reference count.
- Allows deallocation of the object if there are no more strong references.
- Declared using the
weakkeyword. - Always an optional (
Optional) because the referenced object can be nil. - Used to prevent strong reference cycles, especially when one instance can exist independently of another.
class Person { let name: String weak var apartment: Apartment? // Weak reference init(name: String) { self.name = name } deinit { print("\(name) deallocated") } } class Apartment { let unit: String var tenant: Person? // Regular strong reference init(unit: String) { self.unit = unit } deinit { print("Apartment \(unit) deallocated") } } var john: Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") john!.apartment = unit4A unit4A!.tenant = john // Without weak, this would create a strong reference cycle // References are nulled, objects are deallocated john = nil unit4A = nil -
Unowned Reference:
- Does not increase the reference count.
- Allows deallocation if there are no more strong references.
- Declared using the
unownedkeyword. - Not an optional. It is assumed that the referenced object will always exist as long as the instance with the unowned reference exists.
- Accessing an unowned reference after the object has been deallocated will cause a runtime crash.
- Used to prevent strong reference cycles when one instance should always exist as long as another does, and it is not possible for the reference to become nil (e.g.,
selfin closures).
class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { print("\(name) deallocated") } } class CreditCard { let number: UInt64 unowned let customer: Customer // Unowned reference init(number: UInt64, customer: Customer) { self.number = number self.customer = customer } deinit { print("Card #\(number) deallocated") } } var john: Customer? = Customer(name: "John Appleseed") john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!) // If the customer is set to nil, the card referencing it with unowned will become invalid, // but it will not cause a cycle. john = nil // Both objects are deallocated
The choice between weak and unowned depends on the nature of the relationship between objects: use weak when one object may exist without the other (Person without Apartment), and unowned when one object must always exist as long as the other (CreditCard always belongs to a Customer).