diff --git a/React/CxxModule/RCTNativeModule.h b/React/CxxModule/RCTNativeModule.h index 4105894cc98..072c5ca2150 100644 --- a/React/CxxModule/RCTNativeModule.h +++ b/React/CxxModule/RCTNativeModule.h @@ -26,7 +26,6 @@ class RCTNativeModule : public NativeModule { private: __weak RCTBridge *m_bridge; RCTModuleData *m_moduleData; - MethodCallResult invokeInner(unsigned int methodId, const folly::dynamic ¶ms); }; } diff --git a/React/CxxModule/RCTNativeModule.mm b/React/CxxModule/RCTNativeModule.mm index a060d281bc1..4fbe0a14128 100644 --- a/React/CxxModule/RCTNativeModule.mm +++ b/React/CxxModule/RCTNativeModule.mm @@ -25,6 +25,8 @@ namespace facebook { namespace react { +static MethodCallResult invokeInner(RCTBridge *bridge, RCTModuleData *moduleData, unsigned int methodId, const folly::dynamic ¶ms); + RCTNativeModule::RCTNativeModule(RCTBridge *bridge, RCTModuleData *moduleData) : m_bridge(bridge) , m_moduleData(moduleData) {} @@ -56,16 +58,19 @@ folly::dynamic RCTNativeModule::getConstants() { } void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &¶ms, int callId) { + // capture by weak pointer so that we can safely use these variables in a callback + __weak RCTBridge *weakBridge = m_bridge; + __weak RCTModuleData *weakModuleData = m_moduleData; // The BatchedBridge version of this buckets all the callbacks by thread, and // queues one block on each. This is much simpler; we'll see how it goes and // iterate. - dispatch_block_t block = [this, methodId, params=std::move(params), callId] { + dispatch_block_t block = [weakBridge, weakModuleData, methodId, params=std::move(params), callId] { #ifdef WITH_FBSYSTRACE if (callId != -1) { fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId); } #endif - invokeInner(methodId, std::move(params)); + invokeInner(weakBridge, weakModuleData, methodId, std::move(params)); }; dispatch_queue_t queue = m_moduleData.methodQueue; @@ -77,23 +82,23 @@ void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &¶ms, int } MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &¶ms) { - return invokeInner(reactMethodId, params); + return invokeInner(m_bridge, m_moduleData, reactMethodId, params); } -MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly::dynamic ¶ms) { - if (!m_bridge.valid) { +static MethodCallResult invokeInner(RCTBridge *bridge, RCTModuleData *moduleData, unsigned int methodId, const folly::dynamic ¶ms) { + if (!bridge || !bridge.valid || !moduleData) { return folly::none; } - id method = m_moduleData.methods[methodId]; + id method = moduleData.methods[methodId]; if (RCT_DEBUG && !method) { RCTLogError(@"Unknown methodID: %ud for module: %@", - methodId, m_moduleData.name); + methodId, moduleData.name); } NSArray *objcParams = convertFollyDynamicToId(params); @try { - id result = [method invokeWithBridge:m_bridge module:m_moduleData.instance arguments:objcParams]; + id result = [method invokeWithBridge:bridge module:moduleData.instance arguments:objcParams]; return convertIdToFollyDynamic(result); } @catch (NSException *exception) { @@ -104,7 +109,7 @@ MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly NSString *message = [NSString stringWithFormat: @"Exception '%@' was thrown while invoking %s on target %@ with params %@\ncallstack: %@", - exception, method.JSMethodName, m_moduleData.name, objcParams, exception.callStackSymbols]; + exception, method.JSMethodName, moduleData.name, objcParams, exception.callStackSymbols]; RCTFatal(RCTErrorWithMessage(message)); } }