0
0
Swiftprogramming~10 mins

Strong reference cycles between classes in Swift - Step-by-Step Execution

Choose your learning style9 modes available
Concept Flow - Strong reference cycles between classes
Create instance A
Create instance B
A holds strong reference to B
B holds strong reference to A
Reference count of A and B > 0
Neither deinit called -> Memory leak
Strong reference cycle detected
Two class instances hold strong references to each other, preventing deallocation and causing a memory leak.
Execution Sample
Swift
class Person {
  var apartment: Apartment?
  deinit { print("Person deinitialized") }
}

class Apartment {
  var tenant: Person?
  deinit { print("Apartment deinitialized") }
}

var john: Person? = Person()
var unit4A: Apartment? = Apartment()
john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
Creates two classes referencing each other strongly, then sets variables to nil but instances are not deinitialized due to strong reference cycle.
Execution Table
StepActionPerson instance countApartment instance countOutput
1Create Person instance 'john'10
2Create Apartment instance 'unit4A'11
3Set john.apartment = unit4A11
4Set unit4A.tenant = john11
5Set john = nil1 (still referenced by unit4A.tenant)1
6Set unit4A = nil11 (still referenced by john.apartment)
7End of scope, no deinit called11No deinitialization - memory leak
💡 Both instances remain because they strongly reference each other, preventing deallocation.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3After Step 4After Step 5After Step 6Final
johnnilPerson instancePerson instancePerson instancePerson instancenilnilnil
unit4AnilnilApartment instanceApartment instanceApartment instanceApartment instancenilnil
john.apartmentnilnilnilApartment instanceApartment instanceApartment instanceApartment instanceApartment instance
unit4A.tenantnilnilnilnilPerson instancePerson instancePerson instancePerson instance
Key Moments - 3 Insights
Why does setting 'john = nil' not deinitialize the Person instance?
Because 'unit4A.tenant' still holds a strong reference to the Person instance, keeping its reference count above zero (see execution_table step 5).
Why does setting 'unit4A = nil' not deinitialize the Apartment instance?
Because 'john.apartment' still holds a strong reference to the Apartment instance, so its reference count remains above zero (see execution_table step 6).
What causes the memory leak in this example?
The strong reference cycle where Person and Apartment instances hold strong references to each other prevents both from being deallocated (see execution_table step 7).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the Person instance count after setting 'john = nil'?
A1 (still referenced)
B0 (deinitialized)
C2 (duplicated)
Dnil (no instance)
💡 Hint
Check execution_table row 5 under 'Person instance count'
At which step does the Apartment instance remain alive despite setting 'unit4A = nil'?
AStep 4
BStep 6
CStep 5
DStep 7
💡 Hint
Look at execution_table row 6 for 'Apartment instance count'
If we remove the strong reference from 'unit4A.tenant' to 'john', what would happen?
ABoth instances would leak
BApartment instance would leak
CPerson instance would deinitialize when 'john = nil'
DNothing changes
💡 Hint
Removing one strong reference breaks the cycle, allowing deinit (see key_moments about strong references)
Concept Snapshot
Strong reference cycles happen when two class instances hold strong references to each other.
This keeps their reference counts above zero, so neither is deallocated.
In Swift, this causes memory leaks.
Use weak or unowned references to break cycles.
Always check for cycles when classes reference each other.
Full Transcript
This example shows two Swift classes, Person and Apartment, each holding a strong reference to the other. When we create instances and link them, their reference counts increase. Setting the variables 'john' and 'unit4A' to nil does not deinitialize the instances because they still strongly reference each other. This creates a strong reference cycle, causing a memory leak. The execution table tracks the reference counts and shows no deinitialization occurs. To fix this, one reference should be weak or unowned to allow proper deallocation.