Swift DISCUSSION

When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

Started by farhanaziz Swift retain cycleweak selfunownedARC memory managementweak delegate
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

farhanaziz Swift Forum
#1

I have a controller class that owns a Bluetooth manager object and gives it a completion closure that updates the controller's state. After the screen is closed, the controller's deinit is never called and memory grows each time the screen is opened.

I have seen [weak self] and [unowned self] added to closures, sometimes everywhere. How does the cycle actually form, which closures need a capture list, and how do I prove the leak is fixed?

Community replies 4

Re: When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

#2

Swift classes are reference counted. An object is freed when the number of strong references to it drops to zero. A closure that uses self, even implicitly by touching a property, holds a strong reference to it. If the object also holds the closure, directly in a property or indirectly through something it owns, the two keep each other alive: the controller owns the manager, the manager stores the closure, and the closure holds the controller. No count can reach zero, so deinit never runs. There is no garbage collector to detect the loop.

Re: When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

#3

[weak self] breaks the loop by making the closure's reference weak: it does not add to the count and becomes nil when the object goes away. Inside the closure self is then optional, so the usual opening line is guard let self else { return } (older code writes guard let self = self). The whole pattern is manager.onUpdate = { [weak self] value in guard let self else { return }; self.state = value }.

[unowned self] also avoids the strong reference but assumes the object is still alive; if it is not, the access crashes. Use it only when the closure cannot outlive the object.

Re: When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

#4

You do not need it everywhere. The cycle requires the closure to be stored by something that self keeps alive. Non-escaping closures, such as the ones passed to map, filter, forEach or sorted(by:), run and are discarded before the call returns, so they cannot form a cycle. A one-shot escaping closure that is released after it runs only extends the object's life until then, which is sometimes exactly what you want, for example to finish saving data.

The risky ones are long-lived: handlers stored in properties, repeating timers, notification observers, and subscriptions.

Re: When do I need [weak self] in a Swift closure, and how do I confirm a retain cycle?

#5

Delegates are the same problem without a closure. If the manager keeps a strong delegate reference back to the controller that owns it, that is a cycle. Declare it weak var delegate: ManagerDelegate?, which requires the protocol to be class-bound: protocol ManagerDelegate: AnyObject.

To verify, put deinit { print("controller released") } in the class, open and close the screen, and check that the line prints every time. If it does not, Xcode's memory graph debugger shows which objects are still alive and draws the reference chain holding them, and the Leaks instrument reports cycles as they appear.

TEP COMMUNITY