📖 Scenario: Imagine you are building a simple app that fetches user data asynchronously. You want to avoid memory leaks by using weak self and unowned self patterns inside closures.
🎯 Goal: Learn how to use weak self and unowned self inside closures to prevent strong reference cycles in Swift.
📋 What You'll Learn
Create a class called UserFetcher with a method to fetch user data asynchronously
Use a closure that captures self weakly
Use a closure that captures self unowned
Print the fetched user data inside the closure
💡 Why This Matters
🌍 Real World
Using weak and unowned self is important in iOS apps to prevent memory leaks when using closures for callbacks, animations, or network requests.
💼 Career
Understanding these patterns is essential for Swift developers to write safe, efficient, and leak-free code in real-world app development.
Progress0 / 4 steps
1
Create the UserFetcher class with a fetch method
Create a class called UserFetcher with a method fetchUserData() that takes a closure parameter called completion of type (String) -> Void. Inside the method, call completion with the string "User data loaded".
Swift
Hint
Define a class and a method with a closure parameter. Call the closure with the given string.
2
Add a method using weak self in closure
Inside UserFetcher, add a method called loadUserDataWeak() that calls fetchUserData and uses a closure capturing self weakly. Inside the closure, unwrap self safely and print "Weak self: " followed by the data.
Swift
Hint
Use [weak self] in the closure capture list and unwrap self with guard let.
3
Add a method using unowned self in closure
Inside UserFetcher, add a method called loadUserDataUnowned() that calls fetchUserData and uses a closure capturing self unowned. Inside the closure, print "Unowned self: " followed by the data.
Swift
Hint
Use [unowned self] in the closure capture list and print directly without unwrapping.
4
Call both methods and print output
Create an instance of UserFetcher called fetcher. Call fetcher.loadUserDataWeak() and fetcher.loadUserDataUnowned() to print the outputs.
Swift
Hint
Create an instance and call both methods to see the printed output.
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
Using weak self makes the reference to self optional and allows it to become nil, breaking the cycle.
Final Answer:
To prevent strong reference cycles and allow self to become nil -> Option C
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
Step 1: Recall capture list syntax
Swift uses square brackets with capture specifiers before in in closures.
Step 2: Correct unowned syntax
The correct syntax is [unowned self] in to capture self as unowned.
Final Answer:
[unowned self] in -> Option B
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
Step 1: Analyze weak self capture
The closure captures self weakly, so inside the closure self is optional.
Step 2: Check self lifetime
The example instance is still alive when closure?() is called, so self is not nil.
Final Answer:
not nil -> Option A
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
Step 1: Detect strong reference cycle risk
The closure captures self strongly, and greet is lazy var, so cycle possible.
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.
Final Answer:
Use [unowned self] in closure to avoid strong reference cycle -> Option A
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
Step 1: Understand lifetime of self and closure
If self will definitely exist while closure runs, unowned self is safe and avoids optionals.
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.
Final Answer:
Use unowned self because self will outlive the closure, avoiding optionals -> Option D
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 unknownstrongwhile earning +1 Grip toward your certificate.