From 8935d6e697dffb0971f5a8ee1dfbc580080de3e0 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 16 Feb 2022 04:36:26 -0800 Subject: [PATCH] Fix action sheet callback invoked more than once on iPad (#33099) Summary: iOS will sometimes invoke the UIAlertAction handler for the cancel button more than once on iPad. This can be reproduced relatively easily by having a button that opens an action sheet and spam tapping outside the action sheet while it is opening. Since native module callbacks can only be invoked once this causes the app to crash here https://github.com/facebook/react-native/blob/main/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModule.mm#L206. ## Changelog [iOS] [Fixed] - Fix action sheet callback invoked more than once on iPad Pull Request resolved: https://github.com/facebook/react-native/pull/33099 Test Plan: Tested on iPad simulator to reproduce the crash and verified that this fixes it. Reviewed By: philIip Differential Revision: D34215327 Pulled By: ShikaSD fbshipit-source-id: 6f406e4df737a57e6dd702dd54260aa72eab31d6 --- React/CoreModules/RCTActionSheetManager.mm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/React/CoreModules/RCTActionSheetManager.mm b/React/CoreModules/RCTActionSheetManager.mm index 08c5e68355f73a..e2b579244de69f 100644 --- a/React/CoreModules/RCTActionSheetManager.mm +++ b/React/CoreModules/RCTActionSheetManager.mm @@ -118,6 +118,10 @@ - (void)presentViewController:(UIViewController *)alertController NSInteger index = 0; bool isCancelButtonIndex = false; + // The handler for a button might get called more than once when tapping outside + // the action sheet on iPad. RCTResponseSenderBlock can only be called once so + // keep track of callback invocation here. + __block bool callbackInvoked = false; for (NSString *option in buttons) { UIAlertActionStyle style = UIAlertActionStyleDefault; if ([destructiveButtonIndices containsObject:@(index)]) { @@ -131,7 +135,10 @@ - (void)presentViewController:(UIViewController *)alertController UIAlertAction *actionButton = [UIAlertAction actionWithTitle:option style:style handler:^(__unused UIAlertAction *action) { - callback(@[ @(localIndex) ]); + if (!callbackInvoked) { + callbackInvoked = true; + callback(@[ @(localIndex) ]); + } }]; if (isCancelButtonIndex) { [actionButton setValue:cancelButtonTintColor forKey:@"titleTextColor"];