Customize main thread initialization of native modules
Reviewed By: mhorowitz Differential Revision: D3580025 fbshipit-source-id: 18abc15b894c745f584d91da47035c6db036aafa
This commit is contained in:
parent
6ae348e8de
commit
47d6d289d4
|
@ -16,8 +16,9 @@ const NativeModules = require('NativeModules');
|
|||
const { UIManager } = NativeModules;
|
||||
|
||||
const findNodeHandle = require('react/lib/findNodeHandle');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
const _takeSnapshot = UIManager.takeSnapshot;
|
||||
invariant(UIManager, 'UIManager is undefined. The native module config is probably incorrect.');
|
||||
|
||||
/**
|
||||
* Capture an image of the screen, window or an individual view. The image
|
||||
|
@ -39,12 +40,13 @@ const _takeSnapshot = UIManager.takeSnapshot;
|
|||
UIManager.takeSnapshot = async function(
|
||||
view ?: 'window' | ReactElement<any> | number,
|
||||
options ?: {
|
||||
width ?: number;
|
||||
height ?: number;
|
||||
format ?: 'png' | 'jpeg';
|
||||
quality ?: number;
|
||||
width ?: number,
|
||||
height ?: number,
|
||||
format ?: 'png' | 'jpeg',
|
||||
quality ?: number,
|
||||
},
|
||||
) {
|
||||
const _takeSnapshot = UIManager.takeSnapshot;
|
||||
if (!_takeSnapshot) {
|
||||
console.warn('UIManager.takeSnapshot is not available on this platform');
|
||||
return;
|
||||
|
|
|
@ -46,9 +46,10 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
{
|
||||
BOOL _wasBatchActive;
|
||||
NSMutableArray<dispatch_block_t> *_pendingCalls;
|
||||
NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
|
||||
NSDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
|
||||
NSArray<RCTModuleData *> *_moduleDataByID;
|
||||
NSArray<Class> *_moduleClassesByID;
|
||||
NSUInteger _modulesInitializedOnMainQueue;
|
||||
RCTDisplayLink *_displayLink;
|
||||
}
|
||||
|
||||
|
@ -99,6 +100,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
|
||||
- (void)start
|
||||
{
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge setUp]", nil);
|
||||
|
||||
dispatch_queue_t bridgeQueue = dispatch_queue_create("com.facebook.react.RCTBridgeQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
dispatch_group_t initModulesAndLoadSource = dispatch_group_create();
|
||||
|
@ -137,9 +140,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
// Asynchronously gather the module config
|
||||
dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
|
||||
if (weakSelf.valid) {
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge moduleConfig", nil);
|
||||
[performanceLogger markStartForTag:RCTPLNativeModulePrepareConfig];
|
||||
config = [weakSelf moduleConfig];
|
||||
[performanceLogger markStopForTag:RCTPLNativeModulePrepareConfig];
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -166,6 +171,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
[strongSelf executeSourceCode:sourceCode];
|
||||
}
|
||||
});
|
||||
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}
|
||||
|
||||
- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
|
||||
|
@ -233,6 +240,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
moduleData = _moduleDataByName[[@"RCT" stringByAppendingString:moduleName]];
|
||||
}
|
||||
if (moduleData) {
|
||||
#if RCT_DEV
|
||||
if ([self.delegate respondsToSelector:@selector(whitelistedModulesForBridge:)]) {
|
||||
NSArray *whitelisted = [self.delegate whitelistedModulesForBridge:self];
|
||||
RCTAssert(!whitelisted || [whitelisted containsObject:[moduleData moduleClass]],
|
||||
@"Required config for %@, which was not whitelisted", moduleName);
|
||||
}
|
||||
#endif
|
||||
return moduleData.config;
|
||||
}
|
||||
return (id)kCFNull;
|
||||
|
@ -240,6 +254,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
|
||||
- (void)initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
|
||||
{
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge initModules]", nil);
|
||||
[_performanceLogger markStartForTag:RCTPLNativeModuleInit];
|
||||
|
||||
NSArray<id<RCTBridgeModule>> *extraModules = nil;
|
||||
|
@ -252,7 +267,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
}
|
||||
|
||||
if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
|
||||
|
||||
// Check for unexported modules
|
||||
static Class *classes;
|
||||
static unsigned int classCount;
|
||||
|
@ -290,6 +304,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
|
||||
|
||||
// Set up moduleData for pre-initialized module instances
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"extraModules", nil);
|
||||
for (id<RCTBridgeModule> module in extraModules) {
|
||||
Class moduleClass = [module class];
|
||||
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
|
||||
|
@ -317,11 +332,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
_javaScriptExecutor = (id<RCTJavaScriptExecutor>)module;
|
||||
}
|
||||
}
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
|
||||
// The executor is a bridge module, but we want it to be instantiated before
|
||||
// any other module has access to the bridge, in case they need the JS thread.
|
||||
// TODO: once we have more fine-grained control of init (t11106126) we can
|
||||
// probably just replace this with [self moduleForClass:self.executorClass]
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"JavaScriptExecutor", nil);
|
||||
if (!_javaScriptExecutor) {
|
||||
id<RCTJavaScriptExecutor> executorModule = [self.executorClass new];
|
||||
RCTModuleData *moduleData = [[RCTModuleData alloc] initWithModuleInstance:executorModule
|
||||
|
@ -333,8 +350,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
// NOTE: _javaScriptExecutor is a weak reference
|
||||
_javaScriptExecutor = executorModule;
|
||||
}
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
|
||||
// Set up moduleData for automatically-exported modules
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"ModuleData", nil);
|
||||
for (Class moduleClass in RCTGetModuleClasses()) {
|
||||
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
|
||||
|
||||
|
@ -367,8 +386,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
_moduleDataByID = [moduleDataByID copy];
|
||||
_moduleDataByName = [moduleDataByName copy];
|
||||
_moduleClassesByID = [moduleClassesByID copy];
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
|
||||
// Synchronously set up the pre-initialized modules
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"extraModules", nil);
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
if (moduleData.hasInstance &&
|
||||
(!moduleData.requiresMainQueueSetup || RCTIsMainQueue())) {
|
||||
|
@ -381,39 +402,79 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
|
|||
(void)[moduleData instance];
|
||||
}
|
||||
}
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
|
||||
// From this point on, RCTDidInitializeModuleNotification notifications will
|
||||
// be sent the first time a module is accessed.
|
||||
_moduleSetupComplete = YES;
|
||||
|
||||
[self prepareModulesWithDispatchGroup:dispatchGroup];
|
||||
|
||||
[_performanceLogger markStopForTag:RCTPLNativeModuleInit];
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}
|
||||
|
||||
- (void)prepareModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
|
||||
{
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge prepareModulesWithDispatch]", nil);
|
||||
|
||||
NSArray<Class> *whitelistedModules = nil;
|
||||
if ([self.delegate respondsToSelector:@selector(whitelistedModulesForBridge:)]) {
|
||||
whitelistedModules = [self.delegate whitelistedModulesForBridge:self];
|
||||
}
|
||||
|
||||
BOOL initializeImmediately = NO;
|
||||
if (dispatchGroup == NULL) {
|
||||
// If no dispatchGroup is passed in, we must prepare everything immediately.
|
||||
// We better be on the right thread too.
|
||||
RCTAssertMainQueue();
|
||||
initializeImmediately = YES;
|
||||
} else if ([self.delegate respondsToSelector:@selector(shouldBridgeInitializeNativeModulesOnCurrentThread:)]) {
|
||||
initializeImmediately = [self.delegate shouldBridgeInitializeNativeModulesOnCurrentThread:self];
|
||||
}
|
||||
|
||||
// Set up modules that require main thread init or constants export
|
||||
[_performanceLogger setValue:0 forTag:RCTPLNativeModuleMainThread];
|
||||
NSUInteger modulesOnMainQueueCount = 0;
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
__weak RCTBatchedBridge *weakSelf = self;
|
||||
if (whitelistedModules && ![whitelistedModules containsObject:[moduleData moduleClass]]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (moduleData.requiresMainQueueSetup || moduleData.hasConstantsToExport) {
|
||||
// Modules that need to be set up on the main thread cannot be initialized
|
||||
// lazily when required without doing a dispatch_sync to the main thread,
|
||||
// which can result in deadlock. To avoid this, we initialize all of these
|
||||
// modules on the main thread in parallel with loading the JS code, so
|
||||
// they will already be available before they are ever required.
|
||||
dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
RCTBatchedBridge *strongSelf = weakSelf;
|
||||
if (!strongSelf.valid) {
|
||||
return;
|
||||
dispatch_block_t block = ^{
|
||||
if (self.valid) {
|
||||
[self->_performanceLogger appendStartForTag:RCTPLNativeModuleMainThread];
|
||||
(void)[moduleData instance];
|
||||
[moduleData gatherConstants];
|
||||
[self->_performanceLogger appendStopForTag:RCTPLNativeModuleMainThread];
|
||||
}
|
||||
};
|
||||
|
||||
[strongSelf->_performanceLogger appendStartForTag:RCTPLNativeModuleMainThread];
|
||||
(void)[moduleData instance];
|
||||
[moduleData gatherConstants];
|
||||
[strongSelf->_performanceLogger appendStopForTag:RCTPLNativeModuleMainThread];
|
||||
});
|
||||
modulesOnMainQueueCount++;
|
||||
if (initializeImmediately && RCTIsMainQueue()) {
|
||||
block();
|
||||
} else {
|
||||
// We've already checked that dispatchGroup is non-null, but this satisifies the
|
||||
// Xcode analyzer
|
||||
if (dispatchGroup) {
|
||||
dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
_modulesInitializedOnMainQueue++;
|
||||
}
|
||||
}
|
||||
|
||||
[_performanceLogger markStopForTag:RCTPLNativeModuleInit];
|
||||
[_performanceLogger setValue:modulesOnMainQueueCount forTag:RCTPLNativeModuleMainThreadUsesCount];
|
||||
[_performanceLogger setValue:_modulesInitializedOnMainQueue forTag:RCTPLNativeModuleMainThreadUsesCount];
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}
|
||||
|
||||
- (void)whitelistedModulesDidChange
|
||||
{
|
||||
[self prepareModulesWithDispatchGroup:NULL];
|
||||
}
|
||||
|
||||
- (void)setUpExecutor
|
||||
|
@ -594,23 +655,22 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
queue:(dispatch_queue_t)queue
|
||||
{
|
||||
if (queue == RCTJSThread) {
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
RCTProfileBeginFlowEvent();
|
||||
RCTAssert(_javaScriptExecutor != nil, @"Need JS executor to schedule JS work");
|
||||
|
||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||
RCTProfileEndFlowEvent();
|
||||
|
||||
RCTBatchedBridge *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge dispatchBlock", @{ @"loading": @(self.loading) });
|
||||
|
||||
if (strongSelf.loading) {
|
||||
[strongSelf->_pendingCalls addObject:block];
|
||||
if (self.loading) {
|
||||
RCTAssert(self->_pendingCalls != nil, @"Can't add pending call, bridge is no longer loading");
|
||||
[self->_pendingCalls addObject:block];
|
||||
} else {
|
||||
block();
|
||||
}
|
||||
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}];
|
||||
} else if (queue) {
|
||||
dispatch_async(queue, block);
|
||||
|
@ -700,11 +760,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
/**
|
||||
* AnyThread
|
||||
*/
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTBatchedBridge enqueueJSCall:]", nil);
|
||||
if (!_valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTBatchedBridge enqueueJSCall:]", nil);
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
[self dispatchBlock:^{
|
||||
[weakSelf _actuallyInvokeAndProcessModule:module method:method arguments:args ?: @[]];
|
||||
|
@ -712,7 +772,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
completion();
|
||||
}
|
||||
} queue:RCTJSThread];
|
||||
|
||||
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"", nil);
|
||||
}
|
||||
|
||||
|
@ -786,7 +845,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
[_javaScriptExecutor callFunctionOnModule:module
|
||||
method:method
|
||||
arguments:args
|
||||
|
@ -800,7 +859,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
[_javaScriptExecutor invokeCallbackID:cbID
|
||||
arguments:args
|
||||
callback:^(id json, NSError *error) {
|
||||
|
@ -926,7 +985,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
- (void)partialBatchDidFlush
|
||||
{
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
if (moduleData.implementsPartialBatchDidFlush) {
|
||||
if (moduleData.hasInstance && moduleData.implementsPartialBatchDidFlush) {
|
||||
[self dispatchBlock:^{
|
||||
[moduleData.instance partialBatchDidFlush];
|
||||
} queue:moduleData.methodQueue];
|
||||
|
@ -938,7 +997,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
{
|
||||
// TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case?
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
if (moduleData.implementsBatchDidComplete) {
|
||||
if (moduleData.hasInstance && moduleData.implementsBatchDidComplete) {
|
||||
[self dispatchBlock:^{
|
||||
[moduleData.instance batchDidComplete];
|
||||
} queue:moduleData.methodQueue];
|
||||
|
|
|
@ -126,6 +126,17 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
|||
*/
|
||||
- (BOOL)moduleIsInitialized:(Class)moduleClass;
|
||||
|
||||
/**
|
||||
* Call when your delegate's `whitelistedModulesForBridge:` value has changed.
|
||||
* In response to this, the bridge will instantiate any (whitelisted) native modules
|
||||
* that require main thread initialization, so we don't depend on dispatch_sync
|
||||
* later on.
|
||||
*
|
||||
* This method must be called on the main thread, as any pending native modules
|
||||
* will be initialized immediately.
|
||||
*/
|
||||
- (void)whitelistedModulesDidChange;
|
||||
|
||||
/**
|
||||
* All registered bridge module classes.
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#import "RCTLog.h"
|
||||
#import "RCTModuleData.h"
|
||||
#import "RCTPerformanceLogger.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
NSString *const RCTReloadNotification = @"RCTReloadNotification";
|
||||
|
@ -176,7 +177,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
object:nil
|
||||
userInfo:nil];
|
||||
}];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
return [self.batchedBridge moduleIsInitialized:moduleClass];
|
||||
}
|
||||
|
||||
- (void)whitelistedModulesDidChange
|
||||
{
|
||||
[self.batchedBridge whitelistedModulesDidChange];
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
/**
|
||||
|
@ -232,6 +237,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
- (void)setUp
|
||||
{
|
||||
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil);
|
||||
|
||||
// Only update bundleURL from delegate if delegate bundleURL has changed
|
||||
NSURL *previousDelegateURL = _delegateBundleURL;
|
||||
_delegateBundleURL = [self.delegate sourceURLForBridge:self];
|
||||
|
@ -243,6 +250,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
_bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
|
||||
|
||||
[self createBatchedBridge];
|
||||
|
||||
RCT_PROFILE_END_EVENT(0, @"", nil);
|
||||
}
|
||||
|
||||
- (void)createBatchedBridge
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
#import "RCTJavaScriptLoader.h"
|
||||
|
||||
@class RCTBridge;
|
||||
@protocol RCTBridgeModule;
|
||||
|
||||
@protocol RCTBridgeDelegate <NSObject>
|
||||
|
||||
/**
|
||||
|
@ -46,7 +47,28 @@
|
|||
* not recommended in most cases - if the module methods and behavior do not
|
||||
* match exactly, it may lead to bugs or crashes.
|
||||
*/
|
||||
- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge;
|
||||
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge;
|
||||
|
||||
/**
|
||||
* Customize how bridge native modules are initialized. By default all modules are
|
||||
* created lazily except those that have constants to export or require main thread
|
||||
* initialization. If you want to limit the subset of native modules that this
|
||||
* should be considered for, implement this method. Return nil to whitelist all
|
||||
* modules found. Modules passed in extraModulesForBridge: are automatically
|
||||
* whitelisted.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
- (NSArray<Class> *)whitelistedModulesForBridge:(RCTBridge *)bridge;
|
||||
|
||||
/**
|
||||
* When initializing main-thread-only native modules, the bridge will be default
|
||||
* dispatch module creation blocks asynchrously. If we're blockingly waiting on
|
||||
* the main thread to finish bridge creation on the main thread, this will deadlock.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
- (BOOL)shouldBridgeInitializeNativeModulesOnCurrentThread:(RCTBridge *)bridge;
|
||||
|
||||
/**
|
||||
* The bridge will automatically attempt to load the JS source code from the
|
||||
|
|
|
@ -83,14 +83,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
|
||||
- (void)setUpInstanceAndBridge
|
||||
{
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] [_instanceLock lock]", nil);
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] [_instanceLock lock]", @{ @"moduleClass": _moduleClass });
|
||||
[_instanceLock lock];
|
||||
if (!_setupComplete && _bridge.valid) {
|
||||
if (!_instance) {
|
||||
if (RCT_DEBUG && _requiresMainQueueSetup) {
|
||||
RCTAssertMainQueue();
|
||||
}
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] [_moduleClass new]", nil);
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] [_moduleClass new]", @{ @"moduleClass": _moduleClass });
|
||||
_instance = [_moduleClass new];
|
||||
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"", nil);
|
||||
if (!_instance) {
|
||||
|
@ -216,6 +216,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
// get accessed by client code during bridge setup, and a very low risk of
|
||||
// deadlock is better than a fairly high risk of an assertion being thrown.
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData instance] main thread setup", nil);
|
||||
|
||||
if (!RCTIsMainQueue()) {
|
||||
RCTLogError(@"RCTBridge required dispatch_sync to load %@. This may lead to deadlocks", _moduleClass);
|
||||
}
|
||||
RCTExecuteOnMainThread(^{
|
||||
[self setUpInstanceAndBridge];
|
||||
}, YES);
|
||||
|
@ -278,6 +282,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
if (_hasConstantsToExport && !_constantsToExport) {
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, [NSString stringWithFormat:@"[RCTModuleData gatherConstants] %@", _moduleClass], nil);
|
||||
(void)[self instance];
|
||||
if (!RCTIsMainQueue()) {
|
||||
RCTLogError(@"Required dispatch_sync to load constants for %@. This may lead to deadlocks", _moduleClass);
|
||||
}
|
||||
RCTExecuteOnMainThread(^{
|
||||
self->_constantsToExport = [self->_instance constantsToExport] ?: @{};
|
||||
}, YES);
|
||||
|
|
Loading…
Reference in New Issue