-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Description
When navigating back from a screen that contains react-native-pager-view (via @react-navigation/material-top-tabs) with gesture handlers registered by child components (e.g. react-native-draggable-flatlist), the app crashes with SIGABRT on iOS.
The crash occurs in RNGestureHandlerRegistry.m inside attachHandlerWithTag:toView:withActionType:withHostDetector:. During the pager-view teardown, UIKit reshuffles the view hierarchy, which triggers RNGestureHandlerDetector.willMoveToWindow:. When the detector's view is temporarily re-added to a window during teardown, the willMoveToWindow: handler tries to re-attach gesture handlers that have already been dropped from the registry, resulting in a crash.
In RNGH v2 this code path did not exist — RNGestureHandlerDetector is new in v3.
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 6 Abort trap: 6
Thread 0 Crashed:
...
4 RNGestureHandler -[RNGestureHandlerRegistry attachHandlerWithTag:toView:withActionType:withHostDetector:]
(RNGestureHandlerRegistry.m:41)
5 RNGestureHandler -[RNGestureHandlerDetector attachHandlers:actionType:viewTag:attachedHandlers:]
6 RNGestureHandler -[RNGestureHandlerDetector willMoveToWindow:]
7 UIKitCore -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:]
...
13 PagerView -[RCTPagerViewComponentView unmountChildComponentView:index:]
14 PagerView -[RCTPagerViewComponentView goTo:animated:]
15 PagerView -[RCTPagerViewComponentView setPagerViewControllers]
Root cause analysis
In RNGestureHandlerDetector.mm, the willMoveToWindow: method (line ~46) is called when UIKit moves views between windows during teardown. When newWindow != nil (view temporarily re-entering a window), the detector calls attachHandlers:actionType:viewTag:attachedHandlers:, which calls RNGestureHandlerRegistry.attachHandlerWithTag:toView:withActionType:withHostDetector:.
At this point, the gesture handlers referenced by props.handlerTags have already been dropped from the _handlers dictionary via dropHandlerWithTag:, so the lookup returns nil. In the original code, this triggered an RCTAssert that caused the SIGABRT.
Note: PR #3247 fixed a similar issue in RNGestureHandlerManager.mm for the dispatch_after retry path (StrictMode), but did not fix this separate code path in RNGestureHandlerRegistry.m / RNGestureHandlerDetector.mm.
Workaround
Replace the RCTAssert in RNGestureHandlerRegistry.m attachHandlerWithTag:toView:withActionType:withHostDetector: with a nil-check + early return:
- (void)attachHandlerWithTag:(NSNumber *)handlerTag
toView:(RNGHUIView *)view
withActionType:(RNGestureHandlerActionType)actionType
withHostDetector:(nullable RNGHUIView *)hostDetector
{
RNGestureHandler *handler = _handlers[handlerTag];
if (handler == nil) {
return; // Handler was already dropped — safe to skip
}
// ... rest of method
}
Steps to reproduce
- Create a screen using createMaterialTopTabNavigator (backed by react-native-pager-view)
- In one of the tab screens, use a component that registers gesture handlers (e.g. react-native-draggable-flatlist or any GestureDetector)
- Navigate to this screen
- Press back / navigate away from the screen
- App crashes with SIGABRT
A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.
Gesture Handler version
3.0.0-beta.2
React Native version
0.84.1
Platforms
iOS
JavaScript runtime
Hermes
Workflow
React Native (without Expo)
Architecture
New Architecture (Fabric)
Build type
Debug mode
Device
iOS simulator
Device model
No response
Acknowledgements
Yes