From 731bd95c430c752126aaaa34e4911ba2b87b382f Mon Sep 17 00:00:00 2001 From: Phillip Pan Date: Thu, 12 Sep 2024 22:57:11 -0700 Subject: [PATCH] do not iterate through moduleData array to handle UIManager batch completion (#46470) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46470 Changelog: [iOS][Deprecated] - Deprecating RCTBridgeModule batchDidComplete and adding configuration to disable it batchDidComplete is used for the UIManager to initiate a layout and mount after a callback has been initiated by the bridge. however, we iterate through the whole module array in order to get this single UIManager, which is unnecessary. this also increases risk of a crash because the module array is shared between threads. Reviewed By: realsoelynn Differential Revision: D62600034 fbshipit-source-id: 6c98df7d5ab282015181fb07764121693bcc141e --- packages/react-native/React/Base/RCTBridge.h | 3 +++ packages/react-native/React/Base/RCTBridge.mm | 11 +++++++++ .../react-native/React/Base/RCTBridgeModule.h | 2 +- .../React/CxxBridge/RCTCxxBridge.mm | 24 ++++++++++++++----- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/react-native/React/Base/RCTBridge.h b/packages/react-native/React/Base/RCTBridge.h index 23937c18548..788730bba13 100644 --- a/packages/react-native/React/Base/RCTBridge.h +++ b/packages/react-native/React/Base/RCTBridge.h @@ -77,6 +77,9 @@ void RCTSetTurboModuleInteropBridgeProxyLogLevel(RCTBridgeProxyLoggingLevel logL BOOL RCTTurboModuleInteropForAllTurboModulesEnabled(void); void RCTEnableTurboModuleInteropForAllTurboModules(BOOL enabled); +BOOL RCTBridgeModuleBatchDidCompleteDisabled(void); +void RCTDisableBridgeModuleBatchDidComplete(BOOL disabled); + typedef enum { kRCTGlobalScope, kRCTGlobalScopeUsingRetainJSCallback, diff --git a/packages/react-native/React/Base/RCTBridge.mm b/packages/react-native/React/Base/RCTBridge.mm index f576a6be6ac..9aaf79bd0b9 100644 --- a/packages/react-native/React/Base/RCTBridge.mm +++ b/packages/react-native/React/Base/RCTBridge.mm @@ -169,6 +169,17 @@ void RCTEnableTurboModuleSyncVoidMethods(BOOL enabled) gTurboModuleEnableSyncVoidMethods = enabled; } +static BOOL gBridgeModuleDisableBatchDidComplete = NO; +BOOL RCTBridgeModuleBatchDidCompleteDisabled(void) +{ + return gBridgeModuleDisableBatchDidComplete; +} + +void RCTDisableBridgeModuleBatchDidComplete(BOOL disabled) +{ + gBridgeModuleDisableBatchDidComplete = disabled; +} + BOOL kDispatchAccessibilityManagerInitOntoMain = NO; BOOL RCTUIManagerDispatchAccessibilityManagerInitOntoMain(void) { diff --git a/packages/react-native/React/Base/RCTBridgeModule.h b/packages/react-native/React/Base/RCTBridgeModule.h index a77f7abd229..9595fa3d110 100644 --- a/packages/react-native/React/Base/RCTBridgeModule.h +++ b/packages/react-native/React/Base/RCTBridgeModule.h @@ -346,7 +346,7 @@ RCT_EXTERN_C_END /** * Notifies the module that a batch of JS method invocations has just completed. */ -- (void)batchDidComplete; +- (void)batchDidComplete RCT_DEPRECATED; /** * Notifies the module that the active batch of JS method invocations has been diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm index aeece2d3be0..cce793db1d2 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm +++ b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm @@ -1531,15 +1531,27 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithBundleURL - (void)batchDidComplete { - // TODO #12592471: batchDidComplete is only used by RCTUIManager, - // can we eliminate this special case? - for (RCTModuleData *moduleData in _moduleDataByID) { - if (moduleData.implementsBatchDidComplete) { + if (RCTBridgeModuleBatchDidCompleteDisabled()) { + id uiManager = [self moduleForName:@"UIManager"]; + if ([uiManager respondsToSelector:@selector(batchDidComplete)] && + [uiManager respondsToSelector:@selector(methodQueue)]) { [self dispatchBlock:^{ - [moduleData.instance batchDidComplete]; + [uiManager batchDidComplete]; } - queue:moduleData.methodQueue]; + queue:[uiManager methodQueue]]; + } + } else { + // TODO #12592471: batchDidComplete is only used by RCTUIManager, + // can we eliminate this special case? + for (RCTModuleData *moduleData in _moduleDataByID) { + if (moduleData.implementsBatchDidComplete) { + [self + dispatchBlock:^{ + [moduleData.instance batchDidComplete]; + } + queue:moduleData.methodQueue]; + } } } }