Bird
Raised Fist0
Swiftprogramming~20 mins

Weak self and unowned self patterns in Swift - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Swift Memory Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Swift closure using weak self?

Consider the following Swift code snippet. What will be printed when start() is called?

Swift
class MyClass {
    var value = 10
    func start() {
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else {
                print("self is nil")
                return
            }
            print("Value is \(self.value)")
        }
    }
}

var obj: MyClass? = MyClass()
obj?.start()
obj = nil
sleep(2)
ARuntime crash due to unwrapped nil
Bself is nil
CCompilation error due to weak self usage
DValue is 10
Attempts:
2 left
💡 Hint

Think about what happens to obj before the closure runs.

❓ Predict Output
intermediate
2:00remaining
What happens if you use unowned self but self is nil?

What will happen when the following Swift code runs?

Swift
class MyClass {
    var value = 5
    func start() {
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [unowned self] in
            print("Value is \(self.value)")
        }
    }
}

var obj: MyClass? = MyClass()
obj?.start()
obj = nil
sleep(2)
ARuntime crash due to accessing deallocated self
BPrints "Value is 0"
CPrints "Value is 5"
DCompilation error due to unowned self usage
Attempts:
2 left
💡 Hint

Consider what happens when self is accessed after being deallocated.

🔧 Debug
advanced
2:00remaining
Identify the cause of a retain cycle in this Swift code

Why does the following Swift code cause a memory leak?

Swift
class ViewController {
    var closure: (() -> Void)?
    func setup() {
        closure = {
            print("Value is \(self)")
        }
    }
}

var vc: ViewController? = ViewController()
vc?.setup()
vc = nil
AClosure is not assigned properly causing nil reference
BClosure captures self weakly causing early deallocation
CClosure captures self strongly causing retain cycle
DNo retain cycle, memory is freed correctly
Attempts:
2 left
💡 Hint

Think about how closures capture variables by default in Swift.

📝 Syntax
advanced
2:00remaining
Which option correctly uses weak self in a closure?

Choose the correct syntax to capture self weakly inside a closure.

Swift
class Example {
    func doWork() {
        DispatchQueue.global().async {
            // capture self weakly here
        }
    }
}
ADispatchQueue.global().async { weak self in print(self?.description) }
BDispatchQueue.global().async { [weak self:] in print(self?.description) }
CDispatchQueue.global().async { [weak self] print(self?.description) }
DDispatchQueue.global().async { [weak self] in print(self?.description) }
Attempts:
2 left
💡 Hint

Remember the syntax for capture lists in Swift closures.

🚀 Application
expert
2:00remaining
How many items are in the dictionary after this Swift code runs?

Consider this Swift code. How many items remain in dict after the code runs?

Swift
class MyObject {}

var dict = [String: MyObject]()

func test() {
    let obj1 = MyObject()
    let obj2 = MyObject()
    dict["one"] = obj1
    dict["two"] = obj2
}

test()
dict.removeValue(forKey: "one")

print(dict.count)
A1
B2
C0
DCompilation error due to weak references
Attempts:
2 left
💡 Hint

Think about how dictionary keys and values behave when you remove an entry.

Practice

(1/5)
1. What is the main reason to use weak self inside a closure in Swift?
easy
A. To make self immutable inside the closure
B. To guarantee self will never be nil inside the closure
C. To prevent strong reference cycles and allow self to become nil
D. To create a copy of self for thread safety

Solution

  1. Step 1: Understand strong reference cycles

    Strong reference cycles happen when closures capture self strongly, causing memory leaks.
  2. Step 2: Role of weak self

    Using weak self makes the reference to self optional and allows it to become nil, breaking the cycle.
  3. Final Answer:

    To prevent strong reference cycles and allow self to become nil -> Option C
  4. Quick Check:

    Weak self avoids memory leaks = A [OK]
Hint: Weak self means self can be nil inside closures [OK]
Common Mistakes:
  • Thinking weak self guarantees non-nil self
  • Confusing weak with unowned self
  • Assuming weak self copies self
2. Which of the following is the correct syntax to capture self as unowned in a Swift closure?
easy
A. [weak self] in
B. [unowned self] in
C. [self unowned] in
D. [unowned] self in

Solution

  1. Step 1: Recall capture list syntax

    Swift uses square brackets with capture specifiers before in in closures.
  2. Step 2: Correct unowned syntax

    The correct syntax is [unowned self] in to capture self as unowned.
  3. Final Answer:

    [unowned self] in -> Option B
  4. Quick Check:

    Unowned capture syntax = [unowned self] in [OK]
Hint: Capture lists use square brackets with 'unowned self' [OK]
Common Mistakes:
  • Swapping order like [self unowned]
  • Missing brackets or 'in' keyword
  • Using weak instead of unowned when asked
3. Consider this Swift code snippet:
class Example {
    var closure: (() -> Void)?
    func setup() {
        closure = { [weak self] in
            print(self == nil ? "nil" : "not nil")
        }
    }
}
let example = Example()
example.setup()
example.closure?()
What will be printed when example.closure?() is called?
medium
A. not nil
B. Compilation error
C. nil
D. Runtime crash

Solution

  1. Step 1: Analyze weak self capture

    The closure captures self weakly, so inside the closure self is optional.
  2. Step 2: Check self lifetime

    The example instance is still alive when closure?() is called, so self is not nil.
  3. Final Answer:

    not nil -> Option A
  4. Quick Check:

    Weak self is alive here = not nil [OK]
Hint: If instance exists, weak self is not nil inside closure [OK]
Common Mistakes:
  • Assuming weak self is always nil
  • Confusing weak self with unowned self
  • Expecting runtime crash due to optional
4. Identify the problem in this Swift code and choose the best fix:
class Person {
    var name = "Alice"
    lazy var greet: () -> Void = {
        print("Hello, \(self.name)!")
    }
}
let p = Person()
p.greet()
medium
A. Make greet a regular function instead of closure
B. Use [weak self] in closure to avoid strong reference cycle
C. Use [unowned self] in closure to avoid strong reference cycle
D. No problem; code works fine

Solution

  1. Step 1: Detect strong reference cycle risk

    The closure captures self strongly, and greet is lazy var, so cycle possible.
  2. Step 2: Choose unowned self for non-optional self

    Since self will always exist when greet is called, unowned self is safe and avoids optional unwrapping.
  3. Final Answer:

    Use [unowned self] in closure to avoid strong reference cycle -> Option A
  4. Quick Check:

    Unowned self for guaranteed self = C [OK]
Hint: Use unowned self if self always exists in closure [OK]
Common Mistakes:
  • Ignoring strong reference cycles
  • Using weak self and forcing unwrap unnecessarily
  • Thinking no problem exists
5. You have a Swift class that manages a network request with a closure callback. You want to avoid memory leaks but also avoid optional unwrapping inside the closure. Which pattern should you use and why? Choose the best explanation.
hard
A. Do not capture self at all to avoid any reference issues
B. Use weak self to avoid leaks and unwrap self safely inside closure
C. Use strong self to keep the instance alive during the closure execution
D. Use unowned self because self will outlive the closure, avoiding optionals

Solution

  1. Step 1: Understand lifetime of self and closure

    If self will definitely exist while closure runs, unowned self is safe and avoids optionals.
  2. Step 2: Compare weak vs unowned for this case

    weak self requires optional unwrapping, but unowned self assumes self exists, simplifying code and avoiding leaks.
  3. Final Answer:

    Use unowned self because self will outlive the closure, avoiding optionals -> Option D
  4. Quick Check:

    Unowned self for guaranteed lifetime = A [OK]
Hint: Use unowned if self guaranteed alive, else weak [OK]
Common Mistakes:
  • Using weak self but not unwrapping safely
  • Using strong self causing memory leaks
  • Ignoring self capture causing leaks
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