Refactored module access to allow for lazy loading

Summary: public

The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed.

This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead.

The rules are now as follows:

* Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created
* Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but  `constantsToExport:` will still be called on the main thread.
* All other modules will be initialized lazily when a method is first called on them.

These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily.

I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results:

Out of the 65 modules included in UIExplorer:

* 16 are initialized on the main thread when the bridge is created
* A further 8 are initialized when the config is exported to JS
* The remaining 41 will be initialized lazily on-demand

Reviewed By: jspahrsummers

Differential Revision: D2677695

fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
This commit is contained in:
Nick Lockwood
2015-11-25 03:09:00 -08:00
committed by facebook-github-bot-7
parent bba71f146d
commit 060664fd3d
54 changed files with 761 additions and 651 deletions

View File

@@ -59,6 +59,11 @@ typedef NSArray<id<RCTBridgeModule>> *(^RCTBridgeModuleProviderBlock)(void);
*/
RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
/**
* This function checks if a class has been registered
*/
RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
/**
* Async batched bridge used to communicate with the JavaScript application.
*/
@@ -98,10 +103,18 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
/**
* DEPRECATED: Do not use.
* Retrieve a bridge module instance by name or class. Note that modules are
* lazily instantiated, so calling these methods for the first time with a given
* module name/class may cause the class to be sychronously instantiated,
* blocking both the calling thread and main thread for a short time.
*/
#define RCT_IMPORT_METHOD(module, method) \
_Pragma("message(\"This macro is no longer required\")")
- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForClass:(Class)moduleClass;
/**
* All registered bridge module classes.
*/
@property (nonatomic, copy, readonly) NSArray<Class> *moduleClasses;
/**
* URL of the script that was loaded into the bridge.
@@ -130,11 +143,6 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
*/
@property (nonatomic, readonly) RCTEventDispatcher *eventDispatcher;
/**
* A dictionary of all registered RCTBridgeModule instances, keyed by moduleName.
*/
@property (nonatomic, copy, readonly) NSDictionary *modules;
/**
* The launch options that were used to initialize the bridge.
*/
@@ -150,14 +158,19 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
*/
@property (nonatomic, readonly, getter=isValid) BOOL valid;
/**
* The block passed in the constructor with pre-initialized modules
*/
@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
/**
* Reload the bundle and reset executor & modules. Safe to call from any thread.
*/
- (void)reload;
@end
/**
* These properties and methods are deprecated and should not be used
*/
@interface RCTBridge (Deprecated)
@property (nonatomic, copy, readonly) NSDictionary *modules
__deprecated_msg("Use moduleClasses and/or moduleForName: instead");
@end