react-native-screens: UIViewControllerHierarchyInconsistency

Description

The app has been inactive for around 2 min on a “enter pin code page” leading to that the iPhone has been locked. If the user then unlocks the phone, enter the pin code and press the login button, the app then crashes.

After setting enabledScreen(false), I have not been able to reproduce a crash.

Exception from Bugsnag:

UIViewControllerHierarchyInconsistency: child view controller:<RNScreensViewController: 0x126d2ce00> should have parent view controller:(null) but actual parent is:<UIViewController: 0x125e2a7d0>

0  CoreFoundation   ___exceptionPreprocess
1  libobjc.A.dylib  _objc_exception_throw
2  CoreFoundation   +[NSException raise:format:]
3  UIKitCore        -[UIView(Hierarchy) _associatedViewControllerForwardsAppearanceCallbacks:performHierarchyCheck:isRoot:]
4  UIKitCore        -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:]
5  UIKitCore        -[UIView(Internal) _addSubview:positioned:relativeTo:]
6  UIKitCore        ___67-[UIViewControllerBuiltinTransitionViewAnimator animateTransition:]_block_invoke_2
7  UIKitCore        +[UIView(Animation) performWithoutAnimation:]
8  UIKitCore        ___67-[UIViewControllerBuiltinTransitionViewAnimator animateTransition:]_block_invoke
9  UIKitCore        +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:]
10 UIKitCore        +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:]
11 UIKitCore        -[UIViewControllerBuiltinTransitionViewAnimator animateTransition:]
12 UIKitCore        ____UIViewControllerTransitioningRunCustomTransition_block_invoke_2
13 UIKitCore        +[UIInputResponderController _pinInputViewsForInputResponderController:onBehalfOfResponder:duringBlock:]
14 UIKitCore        ____UIViewControllerTransitioningRunCustomTransition_block_invoke.663
15 UIKitCore        +[UIView(Animation) _setAlongsideAnimations:toRunByEndOfBlock:]
16 UIKitCore        __UIViewControllerTransitioningRunCustomTransition
17 UIKitCore        ___56-[UIPresentationController runTransitionForCurrentState]_block_invoke.491
18 UIKitCore        -[_UIAfterCACommitBlock run]
19 UIKitCore        __runAfterCACommitDeferredBlocks
20 UIKitCore        __cleanUpAfterCAFlushAndRunDeferredBlocks
21 UIKitCore        __afterCACommitHandler
22 CoreFoundation   ___CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
23 CoreFoundation   ___CFRunLoopDoObservers
24 CoreFoundation   ___CFRunLoopRun
25 CoreFoundation   _CFRunLoopRunSpecific
26 GraphicsServices _GSEventRunModal
27 UIKitCore        -[UIApplication _run]
28 UIKitCore        _UIApplicationMain

Screenshots

This is the “breadcrumb” from Bugsnag: Screenshot 2021-05-19 at 01 12 07

Package versions

  • React: 17.0.1
  • React Native: 0.64.1
  • React Native Screens: 3.0.0

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 37 (12 by maintainers)

Commits related to this issue

Most upvoted comments

getting this error only when I enable the fabric name __NSCFConstantString * “UIViewControllerHierarchyInconsistency” 0x000000020be3fdf0

Exception NSException * “A view can only be associated with at most one view controller at a time! View <RNSScreenView: 0x113814000; frame = (0 0; 0 0); layer = <CALayer: 0x2812ead00>> is associated with <RNSScreen: 0x111e15f20>. Clear this association before associating this view with <RNSScreen: 0x11d6873f0>.” 0x0000000281d4e4f0

here is my code

const TestComponent = () => {
  return <Text>TestComponent</Text>;
};
const App = () => {
  return (
    <NavigationContainer>
      <RootStack.Navigator
        screenOptions={{
          headerHideBackButton: true,
        }}
      >
        <RootStack.Screen
          name="Chapter"
          options={{
            title: "Fabric Example",
            headerShown: false,
          }}
          initialParams={{
            index: 0,
            chapterRoute: "Chapter",
            afterChapterRoute: "HeaderDemo",
          }}
          component={TestComponent}
        />
        <RootStack.Screen
          name="HeaderDemo"
          component={TestComponent}
          options={{ title: "Header Demo" }}
        />
      </RootStack.Navigator>
    </NavigationContainer>
  );
};

export default App;

    "react-native": "0.72.1",
    "react-native-screens": "3.22.0",
image

I debugged it and it seems like there is a race condition between Modal and Screen view controllers being attached/detached. I am not sure if we can do anything about it since it comes from asynchronous behaviors of these events. The solution to this is probably adding setTimeout for showing the modal in the new screen, so first the proper native hierarchy of view controllers is established, something like this:

const CrashScreen: FC = () => {
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      setShowModal(true);
    }, 0);
  }, []);

  return (
    <View style={styles.container}>
      <Text>Crash screen</Text>
      <Modal visible={showModal}>
        <View style={styles.container}>
          <Text>Loading</Text>
        </View>
      </Modal>
    </View>
  );
};

Can you check if it resolves the issue?

Here is video of this issue:

https://user-images.githubusercontent.com/20343932/141505520-7345a02a-4238-4a95-90a3-1b893d0ecc1c.mp4

Here is repo for reproduction of this issue:

https://github.com/pt7892/UIViewControllerHierarchyInconsistency-repro

Steps to reproduce:

  1. Start app
  2. Press CrashStack navigation link in bottom navigation tab bar
  3. If issue does not appear, reload metro bundler and try again

Issue is not consistent, but trying couple of times steps from above should trigger this bug

Crash log:

2021-11-12 17:50:09.149613+0100 AwesomeTSProject[62797:5010933] [Presentation] Presenting view controller <RCTModalHostViewController: 0x7f7bdbf40d10> from detached view controller <RNSScreen: 0x7f7bdcb39bb0> is discouraged.

2021-11-12 17:50:09.663118+0100 AwesomeTSProject[62797:5010933] *** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<RNScreensViewController: 0x7f7bdcb29500> should have parent view controller:(null) but actual parent is:<RNSScreen: 0x7f7bdcb29eb0>'

@WoLewicki can we reopen this?

It is not in any release yet. They plan to include it in 0.70.1

I think it is only needed if you open a screen with the modal shown from the beginning since then react-native-screens also changes the native controller hierarchy.

I’ll try to. I have some private libraries in there so will need to remove them first.

On Tue, Jul 6, 2021 at 9:46 AM Wojciech Lewicki @.***> wrote:

@rcase100 https://github.com/rcase100 can you provide an example in a form of a repo so we can work on it? It is hard to get any information from such a snippet unfortunately.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/software-mansion/react-native-screens/issues/944#issuecomment-874825086, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALSRN3VUWETVMNODNGYLZQDTWMJKTANCNFSM45DPWHHQ .