Bird
Raised Fist0
Swiftprogramming~20 mins

Strong reference cycles between classes in Swift - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Strong Reference Cycle Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of code with strong reference cycle
What will be printed when this Swift code runs?
Swift
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
    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 Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
A
Person John Appleseed is initialized
Apartment 4A is initialized
Person John Appleseed is being deinitialized
B
Person John Appleseed is initialized
Apartment 4A is initialized
Person John Appleseed is being deinitialized
Apartment 4A is being deinitialized
C
Person John Appleseed is initialized
Apartment 4A is initialized
DNo output, program crashes
Attempts:
2 left
💡 Hint
Think about what happens when two objects hold strong references to each other.
❓ Predict Output
intermediate
2:00remaining
Breaking strong reference cycle with weak reference
What will be printed when this Swift code runs?
Swift
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 Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
A
Person John Appleseed is initialized
Apartment 4A is initialized
Person John Appleseed is being deinitialized
Apartment 4A is being deinitialized
B
Person John Appleseed is initialized
Apartment 4A is initialized
C
Person John Appleseed is initialized
Apartment 4A is initialized
Apartment 4A is being deinitialized
D
Person John Appleseed is being deinitialized
Apartment 4A is being deinitialized
Attempts:
2 left
💡 Hint
Look at the keyword used for the tenant property.
🔧 Debug
advanced
2:00remaining
Identify the cause of memory leak
Why does this Swift code cause a memory leak?
Swift
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: 1234_5678_9012_3456)
alice!.card = card
card!.customer = alice

alice = nil
card = nil
ABecause the CreditCard number is too large and causes overflow.
BBecause both Customer and CreditCard hold strong references to each other, causing a strong reference cycle.
CBecause the Customer class does not implement deinit properly.
DBecause the variables alice and card are declared as optional.
Attempts:
2 left
💡 Hint
Check how the references between Customer and CreditCard are declared.
❓ Predict Output
advanced
2:00remaining
Output with unowned reference to break cycle
What will be printed when this Swift code runs?
Swift
class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
        print("Customer \(name) is initialized")
    }
    deinit {
        print("Customer \(name) is being deinitialized")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
        print("CreditCard \(number) is initialized")
    }
    deinit {
        print("CreditCard \(number) is being deinitialized")
    }
}

var alice: Customer? = Customer(name: "Alice")
alice!.card = CreditCard(number: 1234_5678_9012_3456, customer: alice!)
alice = nil
A
Customer Alice is initialized
CreditCard 1234567890123456 is initialized
Customer Alice is being deinitialized
CreditCard 1234567890123456 is being deinitialized
B
Customer Alice is initialized
CreditCard 1234567890123456 is initialized
Customer Alice is being deinitialized
C
Customer Alice is initialized
CreditCard 1234567890123456 is initialized
CreditCard 1234567890123456 is being deinitialized
DRuntime error due to unowned reference being nil
Attempts:
2 left
💡 Hint
Unowned references do not increase reference count but assume the referenced object exists.
🧠 Conceptual
expert
2:00remaining
Choosing between weak and unowned references
Which statement best describes when to use weak versus unowned references in Swift to avoid strong reference cycles?
AUse weak when the reference is optional; use unowned when the reference is always nil.
BUse weak only for classes and unowned only for structs.
CUse unowned when you want the reference to increase the reference count; use weak when you want to decrease it.
DUse weak when the reference can become nil during its lifetime; use unowned when the reference is expected to always have a value after initialization.
Attempts:
2 left
💡 Hint
Think about whether the reference might become nil or not during the object's lifetime.

Practice

(1/5)
1.

What causes a strong reference cycle between two Swift classes?

Consider two classes holding references to each other.

easy
A. Neither class holds any reference to the other.
B. One class holds a weak reference and the other a strong reference.
C. Both classes hold strong references to each other, preventing deallocation.
D. Both classes hold weak references to each other.

Solution

  1. Step 1: Understand strong references

    Strong references keep objects alive by increasing their reference count.
  2. Step 2: Identify cycle condition

    If two objects hold strong references to each other, neither can be deallocated, causing a cycle.
  3. Final Answer:

    Both classes hold strong references to each other, preventing deallocation. -> Option C
  4. Quick Check:

    Strong references + mutual hold = cycle [OK]
Hint: Strong references both ways cause cycles; use weak/unowned [OK]
Common Mistakes:
  • Thinking weak references cause cycles
  • Assuming one strong and one weak causes cycle
  • Confusing unowned with strong references
2.

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: ???
}
easy
A. var tenant: Person
B. weak var tenant: Person?
C. unowned var tenant: Person
D. var tenant: Person?

Solution

  1. Step 1: Identify weak reference syntax

    In Swift, weak references are declared with the keyword weak and must be optional.
  2. Step 2: Apply to property

    So, weak var tenant: Person? is correct to avoid strong cycles.
  3. Final Answer:

    weak var tenant: Person? -> Option B
  4. Quick Check:

    Weak + optional = correct syntax [OK]
Hint: Weak references must be optional and use 'weak' keyword [OK]
Common Mistakes:
  • Declaring weak without optional type
  • Using unowned when weak is needed
  • Forgetting 'weak' keyword
3.

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 = nil
medium
A. Person John is being deinitialized Apartment 4A is being deinitialized
B. No output, memory leak occurs
C. Only Person John is being deinitialized
D. Only Apartment 4A is being deinitialized

Solution

  1. Step 1: Analyze references

    Person holds strong reference to Apartment; Apartment holds weak reference to Person.
  2. Step 2: Check deallocation

    Setting both variables to nil breaks strong references, so both objects deinit and print messages.
  3. Final Answer:

    Person John is being deinitialized Apartment 4A is being deinitialized -> Option A
  4. Quick Check:

    Weak reference avoids cycle, both deinit [OK]
Hint: Weak reference breaks cycle; both objects deinit when nil [OK]
Common Mistakes:
  • Expecting memory leak output
  • Thinking only one object deinitializes
  • Ignoring weak reference effect
4.

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 = nil
medium
A. CreditCard's customer property should be declared weak to avoid cycle.
B. Customer's card property should be declared weak to avoid cycle.
C. Both properties should be unowned to avoid cycle.
D. No error; code works fine without changes.

Solution

  1. Step 1: Identify reference types

    Both Customer.card and CreditCard.customer are strong references by default.
  2. Step 2: Find cycle cause

    Since both hold strong references, they create a cycle preventing deallocation.
  3. Step 3: Fix cycle

    Declaring CreditCard.customer as weak var customer: Customer? breaks the cycle.
  4. Final Answer:

    CreditCard's customer property should be declared weak to avoid cycle. -> Option A
  5. Quick Check:

    Weak reference breaks cycle [OK]
Hint: Make one side weak to break cycle, usually the back reference [OK]
Common Mistakes:
  • Making both references weak
  • Making the wrong property weak
  • Ignoring the cycle causing deallocation failure
5.

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?

hard
A. Declare the reference as weak var owner: Owner (non-optional)
B. Declare the reference as unowned var owner: Owner
C. Declare the reference as var owner: Owner (strong reference)
D. Declare the reference as weak var owner: Owner?

Solution

  1. Step 1: Understand ownership requirements

    Since Car must always have an Owner during its lifetime, the reference cannot be optional.
  2. Step 2: Choose reference type

    unowned references are non-optional and do not increase reference count, avoiding cycles.
  3. Step 3: Apply declaration

    Declare unowned var owner: Owner in Car to avoid cycle and ensure non-optional reference.
  4. Final Answer:

    Declare the reference as unowned var owner: Owner -> Option D
  5. Quick Check:

    Unowned + non-optional = correct for guaranteed lifetime [OK]
Hint: Use unowned for non-optional back references to avoid cycles [OK]
Common Mistakes:
  • Using weak with non-optional type (invalid)
  • Using strong reference causing cycle
  • Using weak optional when non-optional needed
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard