iosuiviewcontrollercompletionhandleruipopoverpresentationcontroller

`UIViewController.present` completion handler being called immediately


I am using Xcode 10 Beta 6, so this might just be a bug.


I am trying to present a view controller (colorPickerController) as a popover. Within that view controller I will be able to set some properties, which I want to read once the popover is dismissed.

Here's the code:

Code

In lines 93...97 I define a completion handler.
In line 99 I present the colorPickerController modally, including the completion handler.


When running the code the color picker controller was successfully shown in a popover. But when I tapped outside of the popover (to dismiss it), the callback was not called.

I thought maybe a UIPopoverPresentationController does not dismiss "normally", so I tried manually dismissing the popover before it would do so itself, by calling dismiss in popoverPresentationControllerShouldDismissPopover (line 110).

Now this still didn't work, so I set a breakpoint as seen in the picture, to check if the delegate method is even being called.
That's when I noticed, that when running the app, the completion handler is called right when the popover appears, not when it dismisses.
I was logging Completion handler was called. in the console, before even reaching the breakpoint.

How is this possible?


Solution

  • The way your code is in your question, your updateColor closure is only getting called when the presentation animation finishes, not when the view controller you are presenting is done with whatever it needs to do.

    See the docs for UIViewController.present(_:animated:completion:): https://developer.apple.com/documentation/uikit/uiviewcontroller/1621380-present

    completion

    The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify nil for this parameter.

    Note the "after the presentation finishes" (emphasis mine). This means the closure will be executed literally right after the 0.2 seconds of time it takes to animate the presentation of the new view controller up from the bottom of the screen (or however long it takes and in whatever fashion if you're doing some fancy custom presentation animation).

    To get a callback for when your new view controller is done doing whatever it needs to do, subclass UIViewController (call it, say, ColorPickerViewController), and use delegation of some sort to notify your current view controller to dismiss the color picker view controller (and, presumably, to tell it what color was picked).