Middle
What types of references exist in Swift?
sobes.tech AI
Answer from AI
In Swift, there are three main types of references to class instances:
-
Strong Reference:
- This is the default reference type.
- A strong reference increases the reference count of the object.
- The object will not be deallocated from memory as long as there is at least one strong reference to it.
- The main cause of memory leaks is cyclic strong references (
strong reference cycles).
class Person { let name: String init(name: String) { self.name = name } deinit { print("\(name) is being deinitialized") } } var reference1: Person? = Person(name: "John") // reference1 is now a strong reference, increasing the reference count of Person -
Weak Reference:
- Declared using the
weakkeyword. - Does not increase the reference count of the object.
- Used to prevent
strong reference cycles. - Always an optional (
Optional) because the object it points to can be deallocated at any time. When the object is deallocated, the weak reference automatically becomesnil.
class Apartment { let unit: String weak var tenant: Person? // Weak reference init(unit: String) { self.unit = unit } deinit { print("Apartment \(unit) is being deinitialized") } } var john: Person? = Person(name: "John") var unit4A: Apartment? = Apartment(unit: "4A") john?.apartment = unit4A // If Apartment had a strong reference to Person unit4A?.tenant = john // Weak reference // After releasing strong references, objects will be deallocated john = nil unit4A = nil // Output: "John is being deinitialized", "Apartment 4A is being deinitialized" // If tenant was a strong reference, a memory leak (strong cycle) would occur - Declared using the
-
Unowned Reference:
- Declared using the
unownedkeyword. - Like a weak reference, it does not increase the reference count.
- Used to prevent
strong reference cycles. - Unlike
weak, it is not an optional (Optional) and assumes that the object it points to will exist for the entire "lifetime" of the unowned reference. - If the object it points to is deallocated before the
unownedreference becomes invalid, a runtime error occurs. - Suitable for situations where one object always exists as long as another related object exists (e.g., "parent-child" where the parent owns the child, but the child does not strongly own the parent).
class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { print("\(name) is being deinitialized") } } class CreditCard { let number: Int unowned let customer: Customer // Unowned reference init(number: Int, customer: Customer) { self.number = number self.customer = customer // Safe to assign unowned in init } deinit { print("Card #\(number) is being deinitialized") } } var john: Customer? = Customer(name: "John Doe") john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!) // Reset strong reference to Customer john = nil // Output: "John Doe is being deinitialized", "Card #1234567890123456 is being deinitialized" // The unowned reference to customer in CreditCard was valid as long as customer existed. // If CreditCard outlived Customer and we tried to access customer via the unowned reference, an error would occur. - Declared using the
Key difference between weak and unowned:
weak: the object can benil. Use when the lifetime of objects is not strictly tied (one can exist without the other).unowned: the object cannot benilafter initialization. Use when you are sure that the referenced object will exist at least as long as the referencing object.