Merge allowOffMainQueueRegistration and requiresMainQueueSetup

Reviewed By: fromcelticpark

Differential Revision: D5398021

fbshipit-source-id: 7e721cce579678f4c82582f5068cf46574afe961
This commit is contained in:
Pieter De Baets 2017-07-17 03:36:05 -07:00 committed by Facebook Github Bot
parent 7a4eda2f70
commit 980d5140d6
3 changed files with 11 additions and 23 deletions

View File

@ -58,27 +58,14 @@ typedef id<RCTBridgeModule>(^RCTBridgeModuleProvider)(void);
/** /**
* Returns YES if module instance must be created on the main thread. * Returns YES if module instance must be created on the main thread.
* May be overriden by "allowOffMainQueueRegistration".
*/ */
@property (nonatomic, assign, readonly) BOOL requiresMainQueueSetup; @property (nonatomic, assign) BOOL requiresMainQueueSetup;
/** /**
* Returns YES if module has constants to export. * Returns YES if module has constants to export.
* May be overriden by "allowOffMainQueueRegistration".
*/ */
@property (nonatomic, assign, readonly) BOOL hasConstantsToExport; @property (nonatomic, assign, readonly) BOOL hasConstantsToExport;
/**
* If set to YES, it will force both setup and constants export process
* to explicitly happen off the main queue.
* Overrides "requiresMainQueueSetup" & "hasConstantsToExport"
* Defaults to NO.
*
* @experimental
*/
@property (nonatomic, assign) BOOL allowOffMainQueueRegistration;
/** /**
* Returns the current module instance. Note that this will init the instance * Returns the current module instance. Note that this will init the instance
* if it has not already been created. To check if the module instance exists * if it has not already been created. To check if the module instance exists

View File

@ -44,14 +44,15 @@
objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)]; objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
}); });
// If a module overrides `init` then we must assume that it expects to be
// initialized on the main thread, because it may need to access UIKit.
_requiresMainQueueSetup = !_instance &&
[_moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod;
// If a module overrides `constantsToExport` then we must assume that it // If a module overrides `constantsToExport` then we must assume that it
// must be called on the main thread, because it may need to access UIKit. // must be called on the main thread, because it may need to access UIKit.
_hasConstantsToExport = [_moduleClass instancesRespondToSelector:@selector(constantsToExport)]; _hasConstantsToExport = [_moduleClass instancesRespondToSelector:@selector(constantsToExport)];
// If a module overrides `init` then we must assume that it expects to be
// initialized on the main thread, because it may need to access UIKit.
const BOOL hasCustomInit = !_instance && [_moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod;
_requiresMainQueueSetup = _hasConstantsToExport || hasCustomInit;
} }
- (instancetype)initWithModuleClass:(Class)moduleClass - (instancetype)initWithModuleClass:(Class)moduleClass
@ -101,7 +102,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
if (!_setupComplete && _bridge.valid) { if (!_setupComplete && _bridge.valid) {
if (!_instance) { if (!_instance) {
if (RCT_DEBUG && _requiresMainQueueSetup && !_allowOffMainQueueRegistration) { if (RCT_DEBUG && _requiresMainQueueSetup) {
RCTAssertMainQueue(); RCTAssertMainQueue();
} }
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] Create module", nil); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] Create module", nil);
@ -222,7 +223,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
{ {
if (!_setupComplete) { if (!_setupComplete) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData instanceForClass:%@]", _moduleClass]), nil); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData instanceForClass:%@]", _moduleClass]), nil);
if (_requiresMainQueueSetup && !_allowOffMainQueueRegistration) { if (_requiresMainQueueSetup) {
// The chances of deadlock here are low, because module init very rarely // The chances of deadlock here are low, because module init very rarely
// calls out to other threads, however we can't control when a module might // calls out to other threads, however we can't control when a module might
// get accessed by client code during bridge setup, and a very low risk of // get accessed by client code during bridge setup, and a very low risk of
@ -295,7 +296,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
if (_hasConstantsToExport && !_constantsToExport) { if (_hasConstantsToExport && !_constantsToExport) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData gatherConstants] %@", _moduleClass]), nil); RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData gatherConstants] %@", _moduleClass]), nil);
(void)[self instance]; (void)[self instance];
if (_allowOffMainQueueRegistration) { if (!_requiresMainQueueSetup) {
_constantsToExport = [_instance constantsToExport] ?: @{}; _constantsToExport = [_instance constantsToExport] ?: @{};
} else { } else {
if (!RCTIsMainQueue()) { if (!RCTIsMainQueue()) {

View File

@ -651,7 +651,7 @@ struct RCTInstanceCallback : public InstanceCallback {
continue; continue;
} }
if (moduleData.requiresMainQueueSetup || moduleData.hasConstantsToExport) { if (moduleData.requiresMainQueueSetup) {
// Modules that need to be set up on the main thread cannot be initialized // 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, // 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 // which can result in deadlock. To avoid this, we initialize all of these