

A
In the Allegiant Air iOS app, closures are common in async networking, UI callbacks, and view model bindings. Interviewers want to know whether you can reason about memory ownership in Swift and prevent leaks in production code.
Explain how you manage memory and avoid retain cycles when using closures in Swift.
Your answer should cover:
[weak self] and [unowned self] work, and when to use each.Go beyond saying "use weak self." The interviewer expects you to explain ownership relationships, what happens when self becomes nil, trade-offs between weak and unowned, and common mistakes such as unnecessarily weakening short-lived closures or accidentally crashing with unowned.
Swift uses Automatic Reference Counting (ARC) to track object lifetimes. If two objects hold strong references to each other, neither reference count reaches zero, so the objects are never deallocated.
class A {
var b: B?
}
class B {
var a: A?
}
A closure captures variables from the surrounding scope. When a closure captures self strongly and self also stores that closure, a retain cycle is created because each keeps the other alive.
class FlightStatusViewModel {
var onUpdate: (() -> Void)?
func bind() {
onUpdate = {
self.refreshDisplay()
}
}
func refreshDisplay() {}
}
A weak reference does not increase the reference count and becomes nil automatically when the object is deallocated. Use [weak self] when self may reasonably disappear before the closure runs, such as in async callbacks or UI event handlers.
service.fetchTrips { [weak self] result in
guard let self = self else { return }
self.handle(result)
}
An unowned reference also does not retain the object, but it assumes the object will still exist when accessed. Use [unowned self] only when the closure cannot outlive self; otherwise, accessing it after deallocation causes a crash.
lazy var formatter: () -> String = { [unowned self] in
return self.title
}
Not every closure needs a weak capture. A closure passed to a method and executed immediately usually does not create a cycle, but a closure stored on an object, retained by a timer, task, or subscription often can.
performNow {
self.render()
}
self.onTap = { [weak self] in
self?.render()
}