Pass data back from a modally presented view controller delegate versus closure

This tests decoupled UIKit communication and memory safety. A strong answer outlines a weak delegate protocol and a closure with weak self, contrasting coupling and retain cycles. Red flag: singletons or direct parent references.
What's really being asked
This question probes your understanding of decoupled view controller communication and memory safety in UIKit. The interviewer wants to see if you can implement bidirectional data flow without creating retain cycles or tight coupling. Specifically, they care about protocol-oriented design, reference semantics with ARC, and the tradeoffs between object-oriented delegation and functional closure patterns.
The full answer
First, the delegate pattern: define a ChildVCDelegate protocol with a method like didFinishSelecting(value: String), make the parent conform to it, and assign the parent as the delegate through a weak var delegate property on the child. The child calls delegate?.didFinishSelecting(value:) before or after calling dismiss. Second, the closure approach: declare a var onChildFinished: ((String) -> Void)? property on the child, then in the parent set child.onChildFinished = { [weak self] value in self?.handle(value) } before presenting. Third, a direct comparison: delegation enforces loose coupling and scales better when the child has multiple output events or multiple possible parents, while closures are less boilerplate for a single callback but make the child slightly less reusable because the parent logic is injected directly. Fourth, memory management: emphasize that the delegate must be weak to prevent a retain cycle since the parent holds the child and the child holds the delegate; similarly, the closure must use [weak self] to avoid the parent leaking because the child holds the closure and the closure captures the parent.
The mistakes people make
A major red flag is suggesting the child reach back through presentingViewController as! ParentVC to mutate properties directly. This creates tight coupling and breaks if the presentation style changes. Another anti-pattern is using a singleton or the app delegate as a shared data bucket; this hides dependencies and makes unit testing nearly impossible. Some candidates also forget to mark the delegate as weak, which causes a retain cycle that keeps both view controllers in memory after dismissal. Similarly, omitting [weak self] inside the closure produces the same leak. Finally, using NotificationCenter for simple one-to-one modal communication is over-engineered and harms local reasoning.
What usually comes next
The interviewer may ask how you would handle multiple distinct callbacks from the child, such as a save and a cancel action. They might also ask what happens if you use a struct instead of a class for the delegate, which would fail because protocols used as delegates must be class-bound or use AnyObject to allow weak references. Another common follow-up is how to test this: with a delegate, you can inject a mock conforming to the protocol, while with a closure you can capture a local variable in the test to verify the callback fires. They may also ask about async patterns or Combine publishers as modern alternatives.
A concrete example
Imagine a ProductFilterViewController presented modally from a ProductListViewController. Using delegation, ProductFilterViewController defines FilterDelegate with a method applyFilter(minPrice: Int, maxPrice: Int). ProductListViewController conforms, sets filterVC.delegate = self, and implements applyFilter to reload the collection view with the new range. Using a closure, ProductFilterViewController declares var onApply: ((Int, Int) -> Void)?, and ProductListViewController sets filterVC.onApply = { [weak self] min, max in self?.applyFilter(min: min, max: max) } before presenting. Both dismiss the modal, but the delegate version keeps the filter screen reusable by any screen that conforms to the protocol, whereas the closure version is faster to write for a one-off feature.
Interview question
A modally presented view controller needs to report both Save and Cancel actions back to its parent. Which approach best balances decoupling and memory safety?
- a.Store a strong reference to a delegate protocol so callbacks are guaranteed to fire, and use a single closure with an optional Bool parameter to distinguish events.
- b.Post Save and Cancel notifications through NotificationCenter to avoid direct references between the child and parent.
- c.Define a weak delegate protocol with separate methods for each event, letting any conforming parent handle them without knowing its concrete type.Correct
- d.Inject two closures—one for save and one for cancel—and capture self strongly to prevent premature deallocation.
Why? this is the answer
A weak delegate protocol with multiple methods keeps the child decoupled from any specific parent and avoids retain cycles, which is ideal for several distinct actions. Option D is tempting but dangerous because strong self captures create a retain cycle: the child holds the closure and the closure holds the parent.
Just read this? Test yourself on what you have been reading.
Read the original → matteomanferdini.com
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on ios — each one lists the topics its interview covers.
See open roles