Consider the following Swift code that uses weak references to avoid retain cycles. What will be printed?
class Person { let name: String weak var apartment: Apartment? init(name: String) { self.name = name } deinit { print("Person \(name) is being deinitialized") } } class Apartment { let unit: String var tenant: Person? 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 unit4A!.tenant = john john = nil unit4A = nil
Think about how weak references affect object lifetime and deinitialization.
Because apartment is a weak reference, when john and unit4A are set to nil, both objects are deinitialized. This avoids a retain cycle.
Given the same classes as before, if weak var apartment is changed to var apartment (strong reference), what will be the output after setting john and unit4A to nil?
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("Person \(name) is being deinitialized") } } class Apartment { let unit: String var tenant: Person? 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 unit4A!.tenant = john john = nil unit4A = nil
Consider what happens when two objects strongly reference each other.
Without the weak reference, john and unit4A strongly reference each other, causing a retain cycle. Neither is deinitialized when set to nil.
Examine the code below. It is intended to avoid retain cycles using weak references. However, a retain cycle still occurs. What is the mistake?
class Owner { let name: String weak var pet: Pet? init(name: String) { self.name = name } deinit { print("Owner \(name) deinitialized") } } class Pet { let name: String var owner: Owner? init(name: String) { self.name = name } deinit { print("Pet \(name) deinitialized") } } var alice: Owner? = Owner(name: "Alice") var fluffy: Pet? = Pet(name: "Fluffy") alice!.pet = fluffy fluffy!.owner = alice alice = nil fluffy = nil
Think about which side should hold a weak reference to break the cycle.
The retain cycle occurs because owner in Pet is a strong reference. Making it weak breaks the cycle.
Choose the correct syntax to declare a weak reference to an instance of class Car in Swift.
Remember the order of keywords in Swift property declarations.
The correct syntax places weak before var or let. Since weak references must be variables, weak var is correct.
Analyze the following Swift code. After setting manager and employee to nil, how many objects remain in memory?
class Manager { let name: String var employee: Employee? init(name: String) { self.name = name } deinit { print("Manager \(name) deinitialized") } } class Employee { let name: String weak var manager: Manager? init(name: String) { self.name = name } deinit { print("Employee \(name) deinitialized") } } var manager: Manager? = Manager(name: "Mia") var employee: Employee? = Employee(name: "Eli") manager!.employee = employee employee!.manager = manager manager = nil employee = nil
Consider which references are weak and which are strong.
The manager holds a strong reference to employee, but employee holds a weak reference back. Setting both to nil breaks the cycle and deinitializes both.