How can a PresentingViewController get notified that its PresentedViewController dismissed itself?

Viewed 497

Given:

  • ViewController A that presents ViewController B
  • ViewController B has no reference to ViewController A (except implicitly the presentingViewController property)
  • ViewController B calls dismiss on itself and does nothing else

What I want to achieve:

  • ViewController A wants to know when ViewController B got dismissed in order to clean up some state

Restrictions:

  • I do not want to use KVO
  • I do not want to modify ViewController B or its behavior in any way

What I have found out so far:

  • dismiss(animated:completion:) according to the documentation forwards the call to its presentingViewController. But as it seems dismiss(animated:completion:) is not called, but rather a private method _performCoordinatedPresentOrDismiss:animated:.
  • iOS documentation on presentingViewController is misleading. It says "the view controller that was presented has this property set to the view controller that presented it", but that's not true. In iOS 11, this will always point to the root parent VC of the VC that present was called on. Similarly the documentation on presentedViewController is misleading. It says "the view controller that called the method has this property set to the view controller that it presented", that's not the whole story. Every VC in the hierarchy of the VC (all its parent VCs and child VCs) that called present will point to the same presentedViewController.
2 Answers

In your Controller A , kame it as UINavigationControllerDelegate and with navigationController:didShowViewController mark the presentation of Controller B (isControllerBisPresented = true). When viewDidAppear of B , check if isControllerBisPresented is true.

An ugly workaround would be to use a man-in-the-middle which does something in deinit. So A presents M which embeds B as a childVC. When B dismisses itself, M will be dismissed implicitly as well, so it's deinit method should be called. There it can notify A that it was dismissed.

This is fragile, as some reference cycle could prevent M from being deallocated which would result in A not getting notified. So I'd rather want to find a better solution.

Related