UIKit Crash During Navigation Transition After Changing UIView.appearance().semanticContentAttribute (Arabic RTL) — iOS 17.2.1

  • Device: iPhone 11
  • iOS Version: 17.2.1
  • Frameworks: UIKit, Auto Layout
  • App Behavior: App supports Arabic (RTL). User can switch language in-app. When language is switched, the app sets UIView.appearance().semanticContentAttribute and fully rebuilds the window’s rootViewController.

Problem Summary

I update the global semantic direction only when the user explicitly switches language inside the app — e.g.:

// Only run when user switches language inside the app
UIView.appearance().semanticContentAttribute = .forceRightToLeft // or .forceLeftToRight
// then rebuild the window's rootViewController

I do not change UIView.appearance().semanticContentAttribute during navigation transitions. Despite that, after switching the language (and rebuilding the root), the app sometimes crashes during a subsequent UINavigationController push/pop animation. The crash appears to be caused by UIKit’s Auto Layout engine removing or updating directional constraints while a navigation transition is running.

Crash Log (most relevant portion)

          Crashed: com.apple.main-thread
0  CoreAutoLayout                 0x1372c -[NSISEngine positiveErrorVarForBrokenConstraintWithMarker:errorVar:] + 212
1  CoreAutoLayout                 0x121d4 -[NSISEngine removeConstraintWithMarker:] + 1028
2  CoreAutoLayout                 0x11d78 -[NSLayoutConstraint _removeFromEngine:] + 148
3  UIKitCore                      0x124ba9c __58-[UIView _updateDirectionalConstraintsIfNeededWasFlipped:]_block_invoke_2 + 56
4  UIKitCore                      0x484d4 ___UIViewEnumerateLayoutConstraintsAndAdjustForSelectedLayoutVariables_block_invoke + 296
5  UIKitCore                      0x4801c -[UIView(AdditionalLayoutSupport) _withUnsatisfiableConstraintsLoggingSuspendedIfEngineDelegateExists:] + 112
6  UIKitCore                      0x60830 -[UIView _updateDirectionalConstraintsIfNeededWasFlipped:] + 356
7  UIKitCore                      0x60494 -[UIView setSemanticContentAttribute:] + 148
8  CoreFoundation                 0x31794 __invoking___ + 148
9  CoreFoundation                 0xe6360 -[NSInvocation invokeUsingIMP:] + 332
10 UIKitCore                      0x1d93ec __workaround10030904InvokeWithTarget_block_invoke + 68
11 UIKitCore                      0x250ec +[UIView _performSystemAppearanceModifications:] + 72
12 UIKitCore                      0x3f008 applyInvocationsToTarget + 1004
13 UIKitCore                      0x3dcd4 +[_UIAppearance _applyInvocationsTo:window:matchingSelector:onlySystemInvocations:] + 1180
14 UIKitCore                      0x3d744 __88-[UIView(Internal) _performUpdatesForPossibleChangesOfIdiom:orScreen:traverseHierarchy:]_block_invoke + 68
15 UIKitCore                      0x3d6c4 -[UIView _performUpdatesForPossibleChangesOfIdiom:orScreen:traverseHierarchy:] + 216
16 UIKitCore                      0x3d5a0 -[UIView _didChangeFromIdiomOnScreen:traverseHierarchy:] + 112
17 UIKitCore                      0x11644 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 1220
18 UIKitCore                      0x1142c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 684
19 UIKitCore                      0x1142c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 684
20 UIKitCore                      0x1142c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 684
21 UIKitCore                      0x10eb4 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 124
22 CoreAutoLayout                 0xa514 -[NSISEngine withBehaviors:performModifications:] + 84
23 UIKitCore                      0x10ddc -[UIView _postMovedFromSuperview:] + 504
24 UIKitCore                      0xfa24 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 2200
25 UIKitCore                      0x7a63b8 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke_2 + 1252
26 UIKitCore                      0x41a70 +[UIView(Animation) performWithoutAnimation:] + 76
27 UIKitCore                      0x7a5e84 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 240
28 UIKitCore                      0x12749c +[UIView _performBlockDelayingTriggeringResponderEvents:forScene:] + 176
29 UIKitCore                      0x7a5990 -[_UINavigationParallaxTransition animateTransition:] + 952
30 UIKitCore                      0x291098 ___UIViewControllerTransitioningRunCustomTransition_block_invoke_3 + 52
31 UIKitCore                      0x29100c +[UIKeyboardSceneDelegate _pinInputViewsForKeyboardSceneDelegate:onBehalfOfResponder:duringBlock:] + 96
32 UIKitCore                      0x290f70 ___UIViewControllerTransitioningRunCustomTransition_block_invoke_2 + 196
33 UIKitCore                      0x1d8c8c +[UIView(Animation) _setAlongsideAnimations:toRunByEndOfBlock:] + 180
34 UIKitCore                      0x1d851c _UIViewControllerTransitioningRunCustomTransition + 484
35 UIKitCore                      0x6f5a84 -[UINavigationController _startCustomTransition:] + 3292
36 UIKitCore                      0x1182a8 -[UINavigationController _startDeferredTransitionIfNeeded:] + 496
37 UIKitCore                      0x1179a0 -[UINavigationController __viewWillLayoutSubviews] + 96
38 UIKitCore                      0x117904 -[UILayoutContainerView layoutSubviews] + 172
39 UIKitCore                      0x3297c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1528
40 QuartzCore                     0x66aa8 CA::Layer::layout_if_needed(CA::Transaction*) + 500
41 QuartzCore                     0x66630 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 144
42 QuartzCore                     0x6cb60 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464
43 QuartzCore                     0x65e3c CA::Transaction::commit() + 648
44 QuartzCore                     0x65ae4 CA::Transaction::flush_as_runloop_observer(bool) + 88
45 CoreFoundation                 0x3583c __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
46 CoreFoundation                 0x34244 __CFRunLoopDoObservers + 548
47 CoreFoundation                 0x33960 __CFRunLoopRun + 1028
48 CoreFoundation                 0x33478 CFRunLoopRunSpecific + 608
49 GraphicsServices               0x34f8 GSEventRunModal + 164
50 UIKitCore                      0x22c62c -[UIApplication _run] + 888
51 UIKitCore                      0x22bc68 UIApplicationMain + 340
52 MyApp                        0x46a040 main + 44 (AppDelegate.swift:44)
53 ???                            0x1c8d52dcc (缺少)
        

Questions / Requests

  1. Recommended patterns for in-app language switching (LTR ⇄ RTL) to avoid direction/constraint races during animations? For example:
  • Should semantic direction be applied to the window/root view controller only?
  • Should we avoid rebuilding root during an active transition?
  • Any suggested synchronization (e.g., wait for transitions to finish) or APIs to call after rebuilding?
UIKit Crash During Navigation Transition After Changing UIView.appearance().semanticContentAttribute (Arabic RTL) — iOS 17.2.1
 
 
Q