Sobes.tech
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:

  1. 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
    
  2. Weak Reference:

    • Declared using the weak keyword.
    • 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 becomes nil.
    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
    
  3. Unowned Reference:

    • Declared using the unowned keyword.
    • 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 unowned reference 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.
    

Key difference between weak and unowned:

  • weak: the object can be nil. Use when the lifetime of objects is not strictly tied (one can exist without the other).
  • unowned: the object cannot be nil after initialization. Use when you are sure that the referenced object will exist at least as long as the referencing object.
What types of references exist in Swift? — iOS - sobes.tech