UIPercentDrivenInteractiveTransition can cause dismissal transition to stall if interactive part finishes before status bar crossfade animation

Originator:keithbsmiley
Number:rdar://33069344 Date Originated:29-Jun-2017 19:19
Status:Open Resolved:
Product:iOS + SDK Product Version:iOS 11 beta 2
Classification:Serious Bug Reproducible:Sometimes
 
Summary:
This is a duplicate of radar #21961293

Consider the following setup:
1. There's a modal view controller, dismissed using a simple custom transition.
2. UIPercentDrivenInteractiveTransition is used to drive the interactive part of the dismissal, controlled via a pan gesture recognizer.
3. Dismissed view controller has a different status bar style than the presenting view controller and is configured to capture status bar appearance.

Prior to iOS 8.3, status bar transition during view controller dismissal happened instantly. Starting from iOS 8.3, there's now a crossfade animation. However, if the interactive part of the dismissal happens too quickly and "finishInteractiveTransition" or "cancelInteractiveTransition" method of UIPercentDrivenInteractiveTransition is thus called *before* status bar crossfade finishes, the non-interactive part of the transition never completes. As a result, in this scenario:
- Completion block of the custom transition animation is never called.
- Thus, transition is never completed.
- Completion block of "dismissViewControllerAnimated:completion:" method is never called.
- "viewDidDisappear:" method of dismissed view controller is never called.
- Most critically, the dismissed view controller's view is not removed from the view hierarchy, view hierarchy is left in inconsistent state, and user interaction is completely disabled.

Additionally, it seems like starting from iOS 8.3, the value of "modalPresentationCapturesStatusBarAppearance" property is ignored, and view controllers presented modally using a custom transition always capture status bar appearance.


Steps to Reproduce:
1. Create an app with two view controllers: the first one being the root view controller, the second one presented modally on top of the first upon user action.
2. Configure the modal view controller to use a custom modal presentation style and a transitioning delegate that returns a simple custom animator object that animates dismissal using a simple UIView block animation.
3. Configure the transitioning delegate to use UIPercentDrivenInteractiveTransition object that's being controlled by user interaction via a pan gesture recognizer attached to the modal view controller's view.
4. Make modal view controller use a different status bar style than the presenting view controller.
5. Present the modal view controller. After it's presented, **quickly** (in less that 300ms) dismiss it using the pan gesture (interactive transition).

Expected Results:
When interactive part of the animation finishes, the non-interactive part completes the transition animation, all completion blocks are called and dismissal completes.

Actual Results:
When interactive part of the animation finishes, the non-interactive part visually completes the animation, but no completion blocks are called and dismissal never completes, leaving view hierarchy in inconsistent state and user interaction completely disabled.

Version:
iOS 11 beta 2

Notes:
Please use the attached demo project to see the bug in action. Follow the instructions, console logs and comments in code. https://github.com/vlas-voloshin/InteractiveDismissalBug http://www.openradar.me/21961293

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!