0
0
Swiftprogramming~15 mins

Weak self and unowned self patterns in Swift - Deep Dive

Choose your learning style9 modes available
Overview - Weak self and unowned self patterns
What is it?
In Swift programming, weak self and unowned self are ways to refer to an object inside a closure without creating a strong reference that causes a memory cycle. They help manage memory by preventing retain cycles, which happen when two objects keep each other alive forever. Weak self is an optional reference that can become nil, while unowned self is a non-optional reference that assumes the object will always exist when accessed.
Why it matters
Without weak or unowned self, closures can cause memory leaks by holding strong references to objects, making them never get cleaned up. This wastes memory and can slow down or crash apps. Using these patterns ensures your app uses memory efficiently and avoids bugs related to objects living longer than they should.
Where it fits
Before learning this, you should understand Swift closures and reference counting basics. After this, you can learn about advanced memory management, ARC optimization, and how to design safe asynchronous code in Swift.
Mental Model
Core Idea
Weak and unowned self let closures refer to objects without owning them, preventing memory cycles while controlling if the object can disappear or must always exist.
Think of it like...
Imagine lending your car keys to a friend (closure). Weak self is like giving them a spare key that might get lost or taken back anytime, so they might not always have the car. Unowned self is like giving them the main key but trusting they will always have the car; if the car is gone, the key becomes useless and causes trouble.
Closure capturing self references:

┌─────────────┐       strong       ┌─────────────┐
│   Closure   │ ───────────────▶ │    Object   │
└─────────────┘                  └─────────────┘

This strong link can cause a cycle if Object also holds Closure.

Using weak or unowned:

┌─────────────┐  weak/unowned  ┌─────────────┐
│   Closure   │ ─────────────▶ │    Object   │
└─────────────┘                 └─────────────┘

No strong cycle, so Object can be freed.
Build-Up - 7 Steps
1
FoundationUnderstanding strong references in Swift
🤔
Concept: Swift uses strong references to keep objects alive, meaning each reference increases the object's count.
In Swift, every time you assign an object to a variable or constant, you create a strong reference. This means the object stays in memory as long as there is at least one strong reference to it. For example: class Person {} var p1: Person? = Person() // strong reference count = 1 var p2 = p1 // strong reference count = 2 p1 = nil // strong reference count = 1 p2 = nil // strong reference count = 0, object deallocated
Result
Objects stay alive while strong references exist and are deallocated when none remain.
Understanding strong references is key because memory leaks happen when strong references form cycles, preventing deallocation.
2
FoundationWhat causes retain cycles with closures
🤔
Concept: Closures capture variables strongly by default, including self, which can cause retain cycles if self also holds the closure.
When a closure captures self strongly, and self holds the closure (like a property), they keep each other alive forever. For example: class ViewController { var closure: (() -> Void)? func setup() { closure = { print(self) // strong capture of self } } } Here, ViewController owns closure, and closure owns ViewController strongly, causing a cycle.
Result
Neither the ViewController nor the closure get deallocated, causing a memory leak.
Recognizing that closures capture self strongly by default helps you see why memory leaks happen in common patterns.
3
IntermediateUsing weak self to break retain cycles
🤔Before reading on: do you think weak self can become nil inside the closure? Commit to your answer.
Concept: Weak self creates a non-owning, optional reference to self inside the closure that can become nil if self is deallocated.
To avoid retain cycles, you can capture self weakly: closure = { [weak self] in guard let self = self else { return } print(self) } Here, self inside the closure is optional and can be nil if the original object is gone. This prevents the closure from keeping self alive.
Result
The closure no longer strongly holds self, so self can be deallocated, avoiding memory leaks.
Knowing weak self is optional and can become nil helps you write safe closures that don’t crash when self disappears.
4
IntermediateUsing unowned self for non-optional references
🤔Before reading on: do you think unowned self can become nil safely? Commit to your answer.
Concept: Unowned self is a non-owning, non-optional reference that assumes self will always exist when the closure runs.
You can capture self as unowned: closure = { [unowned self] in print(self) } This means the closure does not keep self alive, but if self is deallocated before the closure runs, accessing self causes a crash.
Result
The closure avoids retain cycles but risks runtime crashes if self is gone.
Understanding unowned self’s risk helps you choose it only when you are sure self outlives the closure.
5
IntermediateChoosing between weak and unowned self
🤔Before reading on: which is safer to use in asynchronous closures, weak or unowned self? Commit to your answer.
Concept: Weak self is safer because it handles self being nil, while unowned self is more efficient but risky if self disappears.
Use weak self when self might be nil during closure execution, like in async calls. Use unowned self when self is guaranteed to exist, like in synchronous closures or when self owns the closure. Example: // Async safe closure = { [weak self] in guard let self = self else { return } // use self } // Synchronous safe closure = { [unowned self] in // use self }
Result
Choosing correctly prevents crashes and memory leaks.
Knowing when to use weak or unowned self balances safety and performance in your code.
6
AdvancedAvoiding common pitfalls with weak and unowned self
🤔Before reading on: do you think capturing self weakly always prevents crashes? Commit to your answer.
Concept: Weak self can still cause crashes if you force unwrap it without checking, and unowned self can crash if self is deallocated unexpectedly.
Common mistakes: closure = { [weak self] in print(self!) // force unwrap can crash if self is nil } closure = { [unowned self] in // if self is deallocated, crash occurs } Always safely unwrap weak self and only use unowned self when lifetime is guaranteed.
Result
Proper handling avoids runtime crashes and memory leaks.
Understanding the risks of force unwrapping weak self and unowned self misuse prevents subtle bugs.
7
ExpertMemory management internals with weak and unowned references
🤔Before reading on: do you think weak references increase the reference count? Commit to your answer.
Concept: Weak references do not increase the strong reference count but are tracked by the runtime to nil out automatically. Unowned references are like unsafe pointers without runtime tracking.
Swift’s ARC keeps a strong reference count for objects. Weak references do not increase this count but are stored in a side table so that when the object deallocates, weak references are set to nil automatically. Unowned references are raw pointers without this tracking, so accessing them after deallocation causes crashes. This difference explains why weak self is optional and unowned self is not.
Result
Knowing this helps understand performance and safety tradeoffs.
Understanding ARC’s internal handling of weak and unowned references clarifies why their behaviors differ and guides correct usage.
Under the Hood
Swift uses Automatic Reference Counting (ARC) to manage memory. Strong references increase an object's count, keeping it alive. Weak references do not increase this count but are tracked in a side table so that when the object is deallocated, all weak references to it are automatically set to nil. Unowned references are raw pointers without tracking, so they do not become nil automatically and can cause crashes if accessed after deallocation.
Why designed this way?
This design balances safety and performance. Weak references provide safety by automatically nil-ing, preventing dangling pointers but require runtime overhead for tracking. Unowned references avoid this overhead for cases where the programmer guarantees the object’s lifetime, improving performance but risking crashes if misused. This tradeoff allows Swift to be both safe and efficient.
ARC Reference Management:

┌───────────────┐
│   Object      │
│ Strong Count: │
│     2         │
│ Weak Table:   │◀─────────────┐
└───────────────┘              │
                              │
┌───────────────┐     weak ref │
│ Weak Ref #1   │─────────────▶│
└───────────────┘              │
┌───────────────┐              │
│ Weak Ref #2   │─────────────▶│
└───────────────┘              │
                              │
When Strong Count → 0:
  Object deallocates
  Weak refs set to nil

Unowned refs:
  Raw pointers without tracking
  Access after dealloc → crash
Myth Busters - 4 Common Misconceptions
Quick: Does using weak self guarantee your closure will never crash? Commit to yes or no.
Common Belief:Using weak self always prevents crashes because self is optional and can be nil safely.
Tap to reveal reality
Reality:If you force unwrap weak self without checking, the closure can still crash when self is nil.
Why it matters:Ignoring this leads to runtime crashes that are hard to debug, especially in asynchronous code.
Quick: Can unowned self ever become nil safely? Commit to yes or no.
Common Belief:Unowned self is safe because it behaves like a weak reference but without optionals.
Tap to reveal reality
Reality:Unowned self does not become nil; if the object is deallocated, accessing unowned self causes a crash.
Why it matters:Misusing unowned self can cause unexpected app crashes, especially if object lifetimes are not guaranteed.
Quick: Does capturing self weakly always fix retain cycles? Commit to yes or no.
Common Belief:Capturing self weakly in closures always prevents retain cycles and memory leaks.
Tap to reveal reality
Reality:Retain cycles can still occur if other strong references exist or if self is captured strongly elsewhere.
Why it matters:Assuming weak self solves all leaks can cause hidden memory issues and performance problems.
Quick: Is unowned self always more efficient than weak self? Commit to yes or no.
Common Belief:Unowned self is always more efficient because it avoids optional unwrapping and runtime checks.
Tap to reveal reality
Reality:Unowned self avoids runtime nil checks but risks crashes; weak self has overhead but is safer. Efficiency depends on context.
Why it matters:Choosing unowned self blindly for performance can cause instability in your app.
Expert Zone
1
Weak references are stored in a runtime side table, which adds overhead; excessive use can impact performance subtly.
2
Unowned references can be used safely in paired object lifetimes, like delegates, where the delegate always outlives the closure.
3
Swift’s compiler can sometimes optimize unowned references in synchronous contexts, reducing runtime cost compared to weak references.
When NOT to use
Avoid weak or unowned self when the closure does not capture self or when using value types. For long-lived closures where self might disappear unpredictably, prefer weak self. For guaranteed lifetime scenarios, unowned self is suitable. Alternatives include breaking cycles by nil-ing closures or redesigning ownership.
Production Patterns
In production, weak self is common in asynchronous callbacks, timers, and network requests to avoid leaks. Unowned self is used in delegate patterns and synchronous closures where lifetime is guaranteed. Developers often combine weak self with guard statements for safe unwrapping and use unowned self for performance-critical code with strict lifetime control.
Connections
Garbage Collection
Alternative memory management approach
Understanding ARC’s weak and unowned references highlights differences from garbage collection, which automatically detects cycles, showing why Swift needs explicit weak/unowned to manage memory safely.
Pointer Safety in Systems Programming
Similar to safe and unsafe pointers
Unowned references behave like unsafe pointers without automatic nil checks, connecting Swift’s memory safety to low-level pointer management concepts.
Human Relationships and Trust
Trust and responsibility analogy
The choice between weak and unowned self mirrors trust levels in relationships: weak self is cautious and prepared for absence, unowned self assumes constant presence, reflecting risk management in programming.
Common Pitfalls
#1Force unwrapping weak self without checking for nil
Wrong approach:closure = { [weak self] in print(self!) // crashes if self is nil }
Correct approach:closure = { [weak self] in guard let self = self else { return } print(self) }
Root cause:Misunderstanding that weak self is optional and can be nil, leading to unsafe force unwrap.
#2Using unowned self when self might be deallocated before closure runs
Wrong approach:closure = { [unowned self] in print(self) // crashes if self is gone }
Correct approach:closure = { [weak self] in guard let self = self else { return } print(self) }
Root cause:Assuming unowned self is always safe without guaranteeing object lifetime.
#3Not capturing self weakly or unowned in closures that cause retain cycles
Wrong approach:class A { var closure: (() -> Void)? func setup() { closure = { print(self) } // strong capture } }
Correct approach:class A { var closure: (() -> Void)? func setup() { closure = { [weak self] in guard let self = self else { return } print(self) } } }
Root cause:Forgetting closures capture self strongly by default, causing retain cycles.
Key Takeaways
Swift closures capture self strongly by default, which can cause memory leaks through retain cycles.
Weak self creates an optional, non-owning reference that prevents retain cycles and safely becomes nil when the object is deallocated.
Unowned self creates a non-optional, non-owning reference that assumes the object always exists, risking crashes if it does not.
Choosing between weak and unowned self depends on whether the object’s lifetime is guaranteed during closure execution.
Proper use of weak and unowned self is essential for safe, efficient memory management in Swift applications.