[weak self] in Swift Closures: Best Practice or Overkill?

Ever found yourself adding [weak self]
to every closure without really thinking?
You're not alone — it's one of the most copy-pasted habits in Swift. But is it always necessary?
Memory management is a critical aspect of Swift development, especially when working with reference types like classes. One common pitfall is the retain cycle, which can lead to memory leaks if not handled correctly. This article explains retain cycles in Swift, how escaping closures contribute to them, and when to use [weak self]
to avoid trouble.
Escaping vs Non-Escaping Closures
Non-escaping closure (default in Swift)
Executed within the function call.
Cannot outlive the function.
Capturing self
strongly is safe — because everything gets cleaned up after the function ends. So there’s no retain cycle, and memory is safely managed by ARC.
Escaping closure
One way that a closure can escape is by being stored in a variable that’s defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed — the closure needs to escape, to be called later. (https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/)
So, now we know how both escaping and non-escaping closures work. Why is retain cycle risk specifically mentioned with escaping closures? Because escaping closures are the only kind that can create retain cycles.
Classic Retain Cycle Example.
Here is why it causes the retain cycle.
Cycle of strong references
Now no object in that cycle can be deallocated, because each is keeping the others alive — that’s a retain cycle, and it causes a memory leak.
Magic to fix this?
Here is when [weak self] plays the important role.
When Does a Memory Leak Happen?
A memory leak occurs when objects reference each other in a cycle of strong references, so ARC can’t deallocate them — even though they’re no longer used.
What happened with [weak self]?
The closure holds a weak reference to self. Weak references do not increase the retain count. self
(e.g. UserViewModel
) can be deallocated as soon as it’s no longer used elsewhere. Since we were forced to use self? instead of self, even if the UserViewModel
is deallocated from memory, it will not cause the crash.
Summary
Do we need [weak self] in all the closure. You do not need [weak self]
when: The closure is non-escaping (default in Swift). The closure is escaping but short-lived and not retained. The closure does not capture self.
You only need [weak self]
when the closure is escaping (i.e., it may outlive the function it’s passed into) The closure is stored or retained (e.g., for callbacks, reuse, or async operations) The closure captures self.
If all three conditions are met, use [weak self]
to prevent retain cycles and memory leaks.
Subscribe to my newsletter
Read articles from nyein ei directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
