iOS App multiple UIWindows become unresponsive to touch events after device rotation animation

I am developing an App. There are multiple windows in it. A main window that shows the main UI of the app, and some other util windows that are created dynamically when needed. All of these windows have their rootviewcontrollers, and they all support all the userinterface orientations. But when I rotate the device, the windows seemed rotate to the right orientation, but some window has four strange black rectangles along each side.

And the worse thing is that the whole app become freezed, it does not respond to touch event, I need to force quit it.

I did a lot of experiments to find out the cause of this issue in last two months. I found some truth about this issue:

Good Case:

  1. If the App only has the main window, the issue gone.
  2. If the rotation animation completed, the issue gone.

the attachment shows some callstacks when rotation animation completed.

the rotation animation have 3 steps:



the first



```objc

0   Love2DGameMaker                     0x000000010e8d3e22 $s15Love2DGameMaker27SimulatorRootViewControllerC18viewWillTransition2to4withySo6CGSizeV_So06UIViewgJ11Coordinator_ptF + 754

1   Love2DGameMaker                     0x000000010e8d5dd8 $s15Love2DGameMaker27SimulatorRootViewControllerC18viewWillTransition2to4withySo6CGSizeV_So06UIViewgJ11Coordinator_ptFTo + 72

2   UIKitCore                           0x00007ff8052e4c65 +[UIViewController _performWithoutDeferringTransitionsAllowingAnimation:actions:] + 153

3   UIKitCore                           0x00007ff8052fe5a6 -[UIViewController(AdaptiveSizing_Internal) _window:viewWillTransitionToSize:withTransitionCoordinator:] + 867

4   UIKitCore                           0x00007ff805d10e43 __59-[UIWindow _rotateToBounds:withAnimator:transitionContext:]_block_invoke + 172

5   UIKitCore                           0x00007ff806396494 +[UIView(Animation) performWithoutAnimation:] + 84

6   UIKitCore                           0x00007ff805d10ca3 -[UIWindow _rotateToBounds:withAnimator:transitionContext:] + 446

7   UIKitCore                           0x00007ff805d13f4b -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] + 2044

8   UIKitCore                           0x00007ff805d14509 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 642

9   UIKitCore                           0x00007ff805d0fcf3 -[UIWindow _internal_setRotatableViewOrientation:updateStatusBar:duration:force:] + 113

10  UIKitCore                           0x00007ff805d12120 __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 214

11  UIKitCore                           0x00007ff805d11dc2 -[UIWindow _updateToInterfaceOrientation:duration:force:] + 1166

12  UIKitCore                           0x00007ff804fe4967 -[_UIScenefbsSceneBasedMetricsCalculator _updateMetricsOnWindows:animated:] + 1822

13  UIKitCore                           0x00007ff806017c7e -[UIWindowScene _computeMetricsForWindows:animated:] + 89

14  UIKitCore                           0x00007ff806016c85 __55-[UIWindowScene _computeMetrics:withTransitionContext:]_block_invoke + 133

15  UIKitCore                           0x00007ff806016e16 -[UIWindowScene _computeTraitCollectionAndCoordinateSpaceForcingDelegateCallback:withAction:] + 360

16  UIKitCore                           0x00007ff806016bfa -[UIWindowScene _computeMetrics:withTransitionContext:] + 75

17  UIKitCore                           0x00007ff806013123 -[UIWindowScene _computeMetricsAndCrossFadeInLiveResize:withTransitionContext:] + 231

18  UIKitCore                           0x00007ff806397e43 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 580

19  UIKitCore                           0x00007ff8063980f8 +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:factory:animations:completion:] + 20

20  UIKitCore                           0x00007ff80558439c +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] + 633

21  UIKitCore                           0x00007ff8056f64c3 _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion + 261

22  UIKitCore                           0x00007ff804feb651 -[_UIWindowSceneGeometrySettingsDiffAction _updateSceneGeometryWithSettingObserverContext:windowScene:transitionContext:] + 962

23  UIKitCore                           0x00007ff804feb1c9 -[_UIWindowSceneGeometrySettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 1507

24  UIKitCore                           0x00007ff804dc04db __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.613 + 877

25  UIKitCore                           0x00007ff804dbee90 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 245

26  UIKitCore                           0x00007ff804dc0043 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 252

27  UIKitCore                           0x00007ff8055b9d76 -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 466

28  FrontBoardServices                  0x00007ff807a18b99 -[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:] + 850

29  FrontBoardServices                  0x00007ff807a4caa4 __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2 + 149

30  FrontBoardServices                  0x00007ff807a26a78 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 213

31  FrontBoardServices                  0x00007ff807a4c9dc __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke + 381

32  libdispatch.dylib                   0x000000011441758f _dispatch_client_callout + 8

33  libdispatch.dylib                   0x000000011441af65 _dispatch_block_invoke_direct + 507

34  FrontBoardServices                  0x00007ff807a7635f __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30

35  FrontBoardServices                  0x00007ff807a76239 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 188

36  FrontBoardServices                  0x00007ff807a76387 -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 19

37  CoreFoundation                      0x00007ff800429fb3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17

38  CoreFoundation                      0x00007ff800429ef5 __CFRunLoopDoSource0 + 157

39  CoreFoundation                      0x00007ff8004296f2 __CFRunLoopDoSources0 + 215

40  CoreFoundation                      0x00007ff800423e27 __CFRunLoopRun + 919

41  CoreFoundation                      0x00007ff8004236ad CFRunLoopRunSpecific + 557

42  GraphicsServices                    0x00007ff8103da08f GSEventRunModal + 137

43  UIKitCore                           0x00007ff805cc0ad1 -[UIApplication _run] + 972

44  UIKitCore                           0x00007ff805cc5551 UIApplicationMain + 123

45  UIKitCore                           0x00007ff804d3f563 __swift_destroy_boxed_opaque_existential_1Tm + 10307

46  Love2DGameMaker                     0x000000010e96537b $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 123

47  Love2DGameMaker                     0x000000010e9652f7 $s15Love2DGameMaker11AppDelegateC5$mainyyFZ + 39

48  Love2DGameMaker                     0x000000010e965448 main + 24

49  dyld                                0x000000011132b3e0 start_sim + 10

50  ???                                 0x000000011b37e366 0x0 + 4751614822

```



the second:



```objc

0   Love2DGameMaker                     0x000000010e8d38b0 $s15Love2DGameMaker27SimulatorRootViewControllerC21viewDidLayoutSubviewsyyF + 4656

1   Love2DGameMaker                     0x000000010e8d3b1c $s15Love2DGameMaker27SimulatorRootViewControllerC21viewDidLayoutSubviewsyyFTo + 28

2   UIKitCore                           0x00007ff8063a4980 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2654

3   QuartzCore                          0x00007ff80b18e261 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 527

4   QuartzCore                          0x00007ff80b187623 -[CALayer layoutIfNeeded] + 333

5   UIKitCore                           0x00007ff8052f525f __86-[UIViewController window:willAnimateRotationToInterfaceOrientation:duration:newSize:]_block_invoke + 52

6   UIKitCore                           0x00007ff806397e43 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 580

7   UIKitCore                           0x00007ff806398487 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 25

8   UIKitCore                           0x00007ff8052f51f4 -[UIViewController window:willAnimateRotationToInterfaceOrientation:duration:newSize:] + 337

9   UIKitCore                           0x00007ff8052fe6a8 __104-[UIViewController(AdaptiveSizing_Internal) _window:viewWillTransitionToSize:withTransitionCoordinator:]_block_invoke.3770 + 54

10  UIKitCore                           0x00007ff805308490 -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 145

11  UIKitCore                           0x00007ff805303a9c -[_UIViewControllerTransitionContext __runAlongsideAnimations] + 276

12  UIKitCore                           0x00007ff806397e43 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 580

13  UIKitCore                           0x00007ff806398487 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 25

14  UIKitCore                           0x00007ff805325d3f __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 + 276

15  UIKitCore                           0x00007ff80639c5cd +[UIView _performBlockDelayingTriggeringResponderEvents:forScene:] + 203

16  UIKitCore                           0x00007ff805325acf __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke + 161

17  UIKitCore                           0x00007ff806399647 +[UIView(UIViewAnimationWithBlocksPrivate) _modifyAnimationsWithPreferredFrameRateRange:updateReason:animations:] + 166

18  UIKitCore                           0x00007ff806397e43 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 580

19  UIKitCore                           0x00007ff806398487 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 25

20  UIKitCore                           0x00007ff80532592f -[_UIWindowRotationAnimationController animateTransition:] + 602

21  UIKitCore                           0x00007ff805d10d68 -[UIWindow _rotateToBounds:withAnimator:transitionContext:] + 643

22  UIKitCore                           0x00007ff805d13f4b -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] + 2044

23  UIKitCore                           0x00007ff805d14509 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 642

24  UIKitCore                           0x00007ff805d0fcf3 -[UIWindow _internal_setRotatableViewOrientation:updateStatusBar:duration:force:] + 113

25  UIKitCore                           0x00007ff805d12120 __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 214

26  UIKitCore                           0x00007ff805d11dc2 -[UIWindow _updateToInterfaceOrientation:duration:force:] + 1166

27  UIKitCore                           0x00007ff804fe4967 -[_UIScenefbsSceneBasedMetricsCalculator _updateMetricsOnWindows:animated:] + 1822

28  UIKitCore                           0x00007ff806017c7e -[UIWindowScene _computeMetricsForWindows:animated:] + 89

29  UIKitCore                           0x00007ff806016c85 __55-[UIWindowScene _computeMetrics:withTransitionContext:]_block_invoke + 133

30  UIKitCore                           0x00007ff806016e16 -[UIWindowScene _computeTraitCollectionAndCoordinateSpaceForcingDelegateCallback:withAction:] + 360

31  UIKitCore                           0x00007ff806016bfa -[UIWindowScene _computeMetrics:withTransitionContext:] + 75

32  UIKitCore                           0x00007ff806013123 -[UIWindowScene _computeMetricsAndCrossFadeInLiveResize:withTransitionContext:] + 231

33  UIKitCore                           0x00007ff806397e43 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 580

34  UIKitCore                           0x00007ff8063980f8 +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:factory:animations:completion:] + 20

35  UIKitCore                           0x00007ff80558439c +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] + 633

36  UIKitCore                           0x00007ff8056f64c3 _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion + 261

37  UIKitCore                           0x00007ff804feb651 -[_UIWindowSceneGeometrySettingsDiffAction _updateSceneGeometryWithSettingObserverContext:windowScene:transitionContext:] + 962

38  UIKitCore                           0x00007ff804feb1c9 -[_UIWindowSceneGeometrySettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 1507

39  UIKitCore                           0x00007ff804dc04db __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.613 + 877

40  UIKitCore                           0x00007ff804dbee90 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 245

41  UIKitCore                           0x00007ff804dc0043 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 252

42  UIKitCore                           0x00007ff8055b9d76 -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 466

43  FrontBoardServices                  0x00007ff807a18b99 -[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:] + 850

44  FrontBoardServices                  0x00007ff807a4caa4 __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2 + 149

45  FrontBoardServices                  0x00007ff807a26a78 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 213

46  FrontBoardServices                  0x00007ff807a4c9dc __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke + 381

47  libdispatch.dylib                   0x000000011441758f _dispatch_client_callout + 8

48  libdispatch.dylib                   0x000000011441af65 _dispatch_block_invoke_direct + 507

49  FrontBoardServices                  0x00007ff807a7635f __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30

50  FrontBoardServices                  0x00007ff807a76239 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 188

51  FrontBoardServices                  0x00007ff807a76387 -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 19

52  CoreFoundation                      0x00007ff800429fb3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17

53  CoreFoundation                      0x00007ff800429ef5 __CFRunLoopDoSource0 + 157

54  CoreFoundation                      0x00007ff8004296f2 __CFRunLoopDoSources0 + 215

55  CoreFoundation                      0x00007ff800423e27 __CFRunLoopRun + 919

56  CoreFoundation                      0x00007ff8004236ad CFRunLoopRunSpecific + 557

57  GraphicsServices                    0x00007ff8103da08f GSEventRunModal + 137

58  UIKitCore                           0x00007ff805cc0ad1 -[UIApplication _run] + 972

59  UIKitCore                           0x00007ff805cc5551 UIApplicationMain + 123

60  UIKitCore                           0x00007ff804d3f563 __swift_destroy_boxed_opaque_existential_1Tm + 10307

61  Love2DGameMaker                     0x000000010e96537b $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 123

62  Love2DGameMaker                     0x000000010e9652f7 $s15Love2DGameMaker11AppDelegateC5$mainyyFZ + 39

63  Love2DGameMaker                     0x000000010e965448 main + 24

64  dyld                                0x000000011132b3e0 start_sim + 10

65  ???                                 0x000000011b37e366 0x0 + 4751614822

```



the third:



```objc

0   Love2DGameMaker                     0x000000010e8d5398 $s15Love2DGameMaker27SimulatorRootViewControllerC18viewWillTransition2to4withySo6CGSizeV_So06UIViewgJ11Coordinator_ptFySo0ngjO7Context_pcfU2_ + 376

1   Love2DGameMaker                     0x000000010e8d51a9 $sSo44UIViewControllerTransitionCoordinatorContext_pIegg_SoAA_pIeyBy_TR + 57

2   UIKitCore                           0x00007ff805308490 -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 145

3   UIKitCore                           0x00007ff80530384a -[_UIViewControllerTransitionContext _runAlongsideCompletions] + 126

4   UIKitCore                           0x00007ff805303654 -[_UIViewControllerTransitionContext completeTransition:] + 117

5   UIKitCore                           0x00007ff805325f32 __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2.183 + 26

6   UIKitCore                           0x00007ff80639c5cd +[UIView _performBlockDelayingTriggeringResponderEvents:forScene:] + 203

7   UIKitCore                           0x00007ff805325ed4 __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke.182 + 148

8   UIKitCore                           0x00007ff8063974e0 __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ + 15

9   UIKitCore                           0x00007ff8063977e9 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 775

10  UIKitCore                           0x00007ff806362ca8 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 279

11  UIKitCore                           0x00007ff806363257 -[UIViewAnimationState animationDidStop:finished:] + 276

12  QuartzCore                          0x00007ff80b19bd9a _ZL23run_animation_callbacksPv + 186

13  libdispatch.dylib                   0x000000011441758f _dispatch_client_callout + 8

14  libdispatch.dylib                   0x00000001144273ee _dispatch_main_queue_drain + 1362

15  libdispatch.dylib                   0x0000000114426e8e _dispatch_main_queue_callback_4CF + 31

16  CoreFoundation                      0x00007ff800429af4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9

17  CoreFoundation                      0x00007ff80042442f __CFRunLoopRun + 2463

18  CoreFoundation                      0x00007ff8004236ad CFRunLoopRunSpecific + 557

19  GraphicsServices                    0x00007ff8103da08f GSEventRunModal + 137

20  UIKitCore                           0x00007ff805cc0ad1 -[UIApplication _run] + 972

21  UIKitCore                           0x00007ff805cc5551 UIApplicationMain + 123

22  UIKitCore                           0x00007ff804d3f563 __swift_destroy_boxed_opaque_existential_1Tm + 10307

23  Love2DGameMaker                     0x000000010e96537b $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 123

24  Love2DGameMaker                     0x000000010e9652f7 $s15Love2DGameMaker11AppDelegateC5$mainyyFZ + 39

25  Love2DGameMaker                     0x000000010e965448 main + 24

26  dyld                                0x000000011132b3e0 start_sim + 10

27  ???                                 0x000000011b37e366 0x0 + 4751614822

```

Bad Case:

When the issue occurs, I find out the rotation animation does not complete.

This is some code of rootviewcontroller:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    
    NSLog(@"%s, size: %@", __PRETTY_FUNCTION__, NSStringFromCGSize(size));
    NSLog(@"%@", NSThread.callStackSymbols);
    
    NSLog(@"%@", self.view);
    NSLog(@"%@", self.view.subviews);
    
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        NSLog(@"animation block");
        fprintf(stderr, "stderr animation block\n");
        fprintf(stdout, "stdout animation block\n");
        NSLog(@"%@", NSThread.callStackSymbols);

        NSLog(@"animation block SDL_uikitviewcontroller runloop mode: %@", NSRunLoop.currentRunLoop.currentMode);
        
        NSLog(@"%@", self.view);
        NSLog(@"%@", self.view.subviews);
    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        
        NSLog(@"completion block, isCancelled: %@", context.isCancelled ? @"YES" : @"NO");
        fprintf(stderr, "stderr animation completion block\n");
        fprintf(stdout, "stdout animation completion block\n");
        NSLog(@"%@", NSThread.callStackSymbols);

        NSLog(@"animation complete block SDL_uikitviewcontroller runloop mode: %@", NSRunLoop.currentRunLoop.currentMode);
    }];

    [coordinator notifyWhenInteractionChangesUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }];
    
}

I guess this issue is similar to another common issue: UINavigationController push/pop viewcontroller when previous push/pop animation is running, or showing a UIAlertController when viewcontroller is being pushing/popping

They all have the same result, the app become unresponsive to touch events, but they can respond to other events(I did some test, the app is still running, not in a deadlock state, it just can not respond to touch events)

I guess the root cause of this issue is the animations conflict, or the view hierarchy changed when animating, so the animation states and the view hierarchy were messed up.

But I don't know how to fix it.

I have a workaround, but it has side effect.

I found in the Bad Case, some CAAnimations even not start.

I hooked -[CALayer addAnimation:forKey:], -[UIViewAnimationState animationDidStart], and -[UIViewAnimationState animationDidStop:finished:] methods, and log the info about the layers and animations. By comparing the logs between the good case and bad case, I found that the animations are triggered by the Runloop's CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE function In the bad case, the runloop is running in different mode(actually speaking, in different state, they all run in default mode)

iOS App multiple UIWindows become unresponsive to touch events after device rotation animation
 
 
Q