Weak Reference
A weak reference does not keep an object alive. It is essential when two objects would otherwise retain each other, especially with stored closures and delegates. Weak Reference is a memory-management technique rather than one of the 23 classic patterns.
iOS use case
A child controller stores a callback. Its parent owns the child and wants to react when the child finishes. Capturing the parent strongly in the stored callback would create a cycle.
import UIKit
final class FilterViewController: UIViewController {
var onApply: ((String) -> Void)?
func apply(_ filter: String) {
onApply?(filter)
}
}
final class ResultsViewController: UIViewController {
private var filterController: FilterViewController?
private var selectedFilter = "All"
func showFilters() {
let child = FilterViewController()
child.onApply = { [weak self] filter in
self?.selectedFilter = filter
}
filterController = child
present(child, animated: true)
}
}The parent owns the child; the child's closure only weakly refers back to the parent. When the parent goes away, the callback does nothing safely.
Production decisions
Use weak capture when the callback may outlive the owner and doing nothing after owner deallocation is acceptable. If the operation must complete regardless of the screen lifetime, move it into an independent service instead of relying on a weak view controller. Clear stored callbacks when flows end, and use Instruments' Memory Graph to confirm suspected cycles.
Trace the retain cycle
ResultsViewController stores filterController, keeping the child alive. The child stores onApply. If that closure captured self strongly, the chain would be parent → child → closure → parent and neither controller could deallocate. [weak self] breaks the reverse strong edge. The optional self? means a late callback safely does nothing after the results screen disappears.
From example to a UIKit flow
Set the callback before presenting the filter controller. When Apply fires, update the selected filter and refresh results on the main actor, then dismiss the child and release any strong property that still points to it. If an asynchronous search begins from that callback, let a view model or service own the task; the controller may disappear while the work continues. Weak capture should reflect the desired lifetime, not be sprinkled into every closure without thought.
Failure modes and verification
Use Xcode's Memory Graph or a weak test reference to verify both controllers deallocate after dismissal. A weak capture can accidentally drop important work: if saving must finish even after the screen closes, move saving to an independent owner. Delegate properties are commonly weak for the same reason. Swift value types do not participate in ARC cycles, but closures that capture classes can.