Strong reference cycles happen when two class instances keep each other alive forever. This causes memory to not be freed, which can slow down or crash your app.
Strong reference cycles between classes in Swift
class Person { var name: String var apartment: Apartment? init(name: String) { self.name = name } } class Apartment { var unit: String var tenant: Person? init(unit: String) { self.unit = unit } }
Each class has a property that refers to the other class.
These references are strong by default, which can cause cycles.
var john: Person? = Person(name: "John") var unit4A: Apartment? = Apartment(unit: "4A") john!.apartment = unit4A unit4A!.tenant = john
weak breaks the strong cycle by making one reference weak.class Person { var name: String weak var apartment: Apartment? init(name: String) { self.name = name } } class Apartment { var unit: String var tenant: Person? init(unit: String) { self.unit = unit } }
This program creates two objects that refer to each other strongly. When we set both variables to nil, the objects are not deinitialized because of the strong reference cycle.
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name print("Person \(name) is initialized") } deinit { print("Person \(name) is being deinitialized") } } class Apartment { let unit: String weak var tenant: Person? init(unit: String) { self.unit = unit print("Apartment \(unit) is initialized") } 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
Strong reference cycles cause memory leaks because objects never get freed.
Use weak or unowned to break cycles.
Weak references must be optional because they can become nil.
Strong reference cycles happen when two objects keep strong references to each other.
This stops memory from being freed, causing leaks.
Use weak or unowned to avoid these cycles.
Practice
What causes a strong reference cycle between two Swift classes?
Consider two classes holding references to each other.
Solution
Step 1: Understand strong references
Strong references keep objects alive by increasing their reference count.Step 2: Identify cycle condition
If two objects hold strong references to each other, neither can be deallocated, causing a cycle.Final Answer:
Both classes hold strong references to each other, preventing deallocation. -> Option CQuick Check:
Strong references + mutual hold = cycle [OK]
- Thinking weak references cause cycles
- Assuming one strong and one weak causes cycle
- Confusing unowned with strong references
Which of the following is the correct way to declare a weak reference in Swift to avoid a strong reference cycle?
class Person {
var apartment: Apartment?
}
class Apartment {
// What should go here?
var tenant: ???
}Solution
Step 1: Identify weak reference syntax
In Swift, weak references are declared with the keywordweakand must be optional.Step 2: Apply to property
So,weak var tenant: Person?is correct to avoid strong cycles.Final Answer:
weak var tenant: Person? -> Option BQuick Check:
Weak + optional = correct syntax [OK]
- Declaring weak without optional type
- Using unowned when weak is needed
- Forgetting 'weak' keyword
What will be the output of the following Swift code?
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
weak var tenant: Person?
init(unit: String) { self.unit = unit }
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person? = Person(name: "John")
var apt: Apartment? = Apartment(unit: "4A")
john!.apartment = apt
apt!.tenant = john
john = nil
apt = nilSolution
Step 1: Analyze references
Person holds strong reference to Apartment; Apartment holds weak reference to Person.Step 2: Check deallocation
Setting both variables to nil breaks strong references, so both objects deinit and print messages.Final Answer:
Person John is being deinitialized Apartment 4A is being deinitialized -> Option AQuick Check:
Weak reference avoids cycle, both deinit [OK]
- Expecting memory leak output
- Thinking only one object deinitializes
- Ignoring weak reference effect
Identify the error in the following Swift code that causes a strong reference cycle:
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
deinit { print("Customer \(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
var customer: Customer?
init(number: UInt64) { self.number = number }
deinit { print("CreditCard \(number) is being deinitialized") }
}
var alice: Customer? = Customer(name: "Alice")
var card: CreditCard? = CreditCard(number: 1234567890123456)
alice!.card = card
card!.customer = alice
alice = nil
card = nilSolution
Step 1: Identify reference types
Both Customer.card and CreditCard.customer are strong references by default.Step 2: Find cycle cause
Since both hold strong references, they create a cycle preventing deallocation.Step 3: Fix cycle
Declaring CreditCard.customer asweak var customer: Customer?breaks the cycle.Final Answer:
CreditCard's customer property should be declared weak to avoid cycle. -> Option AQuick Check:
Weak reference breaks cycle [OK]
- Making both references weak
- Making the wrong property weak
- Ignoring the cycle causing deallocation failure
You have two classes, Owner and Car. The Owner has a strong reference to Car, and Car has a strong reference to Owner. You want to avoid a strong reference cycle but also ensure that Car always has an Owner during its lifetime. How should you declare the reference from Car to Owner?
Solution
Step 1: Understand ownership requirements
SinceCarmust always have anOwnerduring its lifetime, the reference cannot be optional.Step 2: Choose reference type
unownedreferences are non-optional and do not increase reference count, avoiding cycles.Step 3: Apply declaration
Declareunowned var owner: OwnerinCarto avoid cycle and ensure non-optional reference.Final Answer:
Declare the reference as unowned var owner: Owner -> Option DQuick Check:
Unowned + non-optional = correct for guaranteed lifetime [OK]
- Using weak with non-optional type (invalid)
- Using strong reference causing cycle
- Using weak optional when non-optional needed
Ready to prove it?
Pass the test and this pattern moves unknown
