Bird
Raised Fist0
Swiftprogramming~5 mins

Closures causing retain cycles in Swift - Cheat Sheet & Quick Revision

Choose your learning style10 modes available
Recall & Review
beginner
What is a retain cycle in Swift closures?
A retain cycle happens when two objects hold strong references to each other, preventing them from being deallocated. In closures, this often occurs when a closure captures self strongly, and self holds the closure, causing a loop.
Click to reveal answer
beginner
How can you prevent retain cycles caused by closures in Swift?
Use a capture list with [weak self] or [unowned self] inside the closure to capture self weakly or unowned, breaking the strong reference cycle.
Click to reveal answer
intermediate
Explain the difference between [weak self] and [unowned self] in closure capture lists.
[weak self] creates an optional reference that can become nil if self is deallocated, so you must unwrap it safely. [unowned self] assumes self will never be nil during closure execution and is non-optional, but can cause a crash if self is deallocated.
Click to reveal answer
beginner
What happens if you don’t use [weak self] or [unowned self] in a closure that captures self?
The closure holds a strong reference to self, and if self also holds the closure, they keep each other alive. This causes a memory leak because neither can be freed.
Click to reveal answer
intermediate
Show a simple Swift example of a retain cycle caused by a closure capturing self strongly.
class MyClass {
  var closure: (() -> Void)?
  func setup() {
    closure = {
      print(self)
    }
  }
}

Here, self holds closure, and closure captures self strongly, causing a retain cycle.
Click to reveal answer
What keyword can you use in a closure capture list to avoid a retain cycle by capturing self weakly?
A[strong self]
B[weak self]
C[unowned self]
D[static self]
What is the risk of using [unowned self] in a closure?
AIt can cause a crash if self is nil when the closure runs.
BIt makes self optional inside the closure.
CIt creates a strong reference cycle.
DIt automatically unwraps self safely.
Why do retain cycles cause memory leaks in Swift?
ABecause closures cannot capture variables.
BBecause weak references increase memory usage.
CBecause objects keep each other alive with strong references.
DBecause ARC disables deallocation.
Which of these is NOT a way to break a retain cycle in closures?
AMaking self a global variable.
BUsing [weak self] in the capture list.
CUsing [unowned self] in the capture list.
DSetting the closure to nil when done.
In the example: closure = { print(self) }, what causes the retain cycle?
AClosure is a global function.
BClosure captures self weakly.
CClosure does not capture self.
DClosure captures self strongly and self holds closure.
Explain what a retain cycle is and how closures can cause them in Swift.
Think about how two things holding strong references to each other can never be freed.
You got /4 concepts.
    Describe how to use capture lists to prevent retain cycles in Swift closures and the difference between weak and unowned captures.
    Focus on how to tell the closure to hold a weaker reference to self.
    You got /5 concepts.

      Practice

      (1/5)
      1. What is the main reason closures cause retain cycles in Swift?
      easy
      A. Closures capture self strongly, preventing deallocation
      B. Closures do not capture variables at all
      C. Closures always run on a background thread
      D. Closures automatically break retain cycles

      Solution

      1. Step 1: Understand closure capturing behavior

        Closures in Swift capture variables, including self, strongly by default.
      2. Step 2: Recognize impact on memory

        If a closure captures self strongly and self holds the closure, neither can be released, causing a retain cycle.
      3. Final Answer:

        Closures capture self strongly, preventing deallocation -> Option A
      4. Quick Check:

        Strong capture causes retain cycle = B [OK]
      Hint: Closures keep strong references by default, causing retain cycles [OK]
      Common Mistakes:
      • Thinking closures do not capture variables
      • Assuming closures run on background threads
      • Believing closures automatically break retain cycles
      2. Which of the following is the correct syntax to declare a closure capturing self weakly in Swift?
      easy
      A. let closure = { weak self in print(self) }
      B. let closure = { (weak self) -> Void in print(self) }
      C. let closure = { [weak self] in print(self) }
      D. let closure = { [self weak] in print(self) }

      Solution

      1. Step 1: Recall capture list syntax

        In Swift, capture lists are declared inside square brackets before the closure body.
      2. Step 2: Identify correct weak capture syntax

        The correct syntax is [weak self] inside the capture list, followed by the closure code.
      3. Final Answer:

        let closure = { [weak self] in print(self) } -> Option C
      4. Quick Check:

        Capture list uses [weak self] = C [OK]
      Hint: Use square brackets for capture lists like [weak self] [OK]
      Common Mistakes:
      • Using parentheses instead of brackets for capture list
      • Writing weak self without brackets
      • Swapping order to [self weak]
      3. Consider this Swift code snippet:
      class MyClass {
          var closure: (() -> Void)?
          func setup() {
              closure = {
                  print(self)
              }
          }
      }
      let obj = MyClass()
      obj.setup()
      
      What is the main problem with this code?
      medium
      A. It runs without any memory issues
      B. It causes a syntax error due to missing capture list
      C. It prints nil because self is not captured
      D. It causes a retain cycle because closure captures self strongly

      Solution

      1. Step 1: Analyze closure capturing self

        The closure assigned to the property captures self strongly by default.
      2. Step 2: Understand retain cycle effect

        Since self holds closure and closure holds self, neither is released, causing a retain cycle and memory leak.
      3. Final Answer:

        It causes a retain cycle because closure captures self strongly -> Option D
      4. Quick Check:

        Strong capture causes retain cycle = A [OK]
      Hint: Closures capturing self strongly cause retain cycles unless weak/unowned used [OK]
      Common Mistakes:
      • Assuming no retain cycle without capture list
      • Thinking it causes syntax error
      • Believing closure prints nil
      4. Given this code, what is the best fix to avoid the retain cycle?
      class ViewController {
          var completion: (() -> Void)?
          func configure() {
              completion = {
                  print(self)
              }
          }
      }
      medium
      A. Call configure() twice
      B. Use [weak self] in the closure capture list
      C. Declare completion as a strong reference
      D. Remove the closure property entirely

      Solution

      1. Step 1: Identify cause of retain cycle

        The closure captures self strongly, causing retain cycle with the property.
      2. Step 2: Apply weak capture to break cycle

        Adding [weak self] in the capture list makes self a weak reference, breaking the cycle.
      3. Final Answer:

        Use [weak self] in the closure capture list -> Option B
      4. Quick Check:

        Weak capture breaks retain cycle = D [OK]
      Hint: Add [weak self] to closure capture list to fix retain cycles [OK]
      Common Mistakes:
      • Removing closure property instead of fixing capture
      • Making completion strong reference (already strong)
      • Calling configure multiple times doesn't fix cycle
      5. You have a class with a closure property that captures self unowned:
      class Worker {
          var task: (() -> Void)?
          func start() {
              task = { [unowned self] in
                  print("Working with \(self)")
              }
          }
      }
      var w: Worker? = Worker()
      w?.start()
      w = nil
      
      What happens when w is set to nil and why?
      hard
      A. Worker instance is deallocated safely; unowned does not retain self
      B. Runtime crash occurs because closure accesses deallocated self
      C. Memory leak occurs due to strong capture
      D. Nothing happens; closure is never called

      Solution

      1. Step 1: Understand unowned capture behavior

        Unowned references do not increase retain count but expect self to exist while closure runs.
      2. Step 2: Analyze deallocation when w = nil

        Setting w to nil releases Worker instance; no retain cycle exists because closure holds unowned self.
      3. Final Answer:

        Worker instance is deallocated safely; unowned does not retain self -> Option A
      4. Quick Check:

        Unowned capture allows safe deallocation = A [OK]
      Hint: Unowned captures don't retain but expect self alive during use [OK]
      Common Mistakes:
      • Confusing unowned with weak causing runtime crash
      • Assuming strong capture causes leak here
      • Thinking closure runs automatically on deallocation
      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