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:
parent
bba71f146d
commit
060664fd3d
|
@ -52,8 +52,7 @@ RCT_EXPORT_MODULE();
|
|||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
_sizeUpdated = NO;
|
||||
|
||||
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
_bridge = [OCMockObject mockForClass:[RCTBridge class]];
|
||||
_eventDispatcher = [RCTEventDispatcher new];
|
||||
((id<RCTBridgeModule>)_eventDispatcher).bridge = _bridge;
|
||||
[_eventDispatcher setValue:_bridge forKey:@"bridge"];
|
||||
|
||||
_eventName = RCTNormalizeInputEventName(@"sampleEvent");
|
||||
_body = @{ @"foo": @"bar" };
|
||||
|
|
|
@ -16,6 +16,15 @@
|
|||
#import "RCTUtils.h"
|
||||
#import "RCTNetworking.h"
|
||||
|
||||
#define RUN_RUNLOOP_WHILE(CONDITION) \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||
NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:5]; \
|
||||
while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
|
||||
} \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
extern BOOL RCTIsGzippedData(NSData *data);
|
||||
|
||||
@interface RCTNetworking (Private)
|
||||
|
@ -61,18 +70,21 @@ extern BOOL RCTIsGzippedData(NSData *data);
|
|||
- (void)testRequestBodyEncoding
|
||||
{
|
||||
NSDictionary *query = @{
|
||||
@"url": @"http://example.com",
|
||||
@"method": @"POST",
|
||||
@"data": @{@"string": @"Hello World"},
|
||||
@"headers": @{@"Content-Encoding": @"gzip"},
|
||||
};
|
||||
@"url": @"http://example.com",
|
||||
@"method": @"POST",
|
||||
@"data": @{@"string": @"Hello World"},
|
||||
@"headers": @{@"Content-Encoding": @"gzip"},
|
||||
};
|
||||
|
||||
RCTNetworking *networker = [RCTNetworking new];
|
||||
[networker setValue:dispatch_get_main_queue() forKey:@"methodQueue"];
|
||||
__block NSURLRequest *request = nil;
|
||||
[networker buildRequest:query completionBlock:^(NSURLRequest *_request) {
|
||||
request = _request;
|
||||
}];
|
||||
|
||||
RUN_RUNLOOP_WHILE(request == nil);
|
||||
|
||||
XCTAssertNotNil(request);
|
||||
XCTAssertNotNil(request.HTTPBody);
|
||||
XCTAssertTrue(RCTIsGzippedData(request.HTTPBody));
|
||||
|
|
|
@ -151,7 +151,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (ALAssetsLibrary *)assetsLibrary
|
||||
{
|
||||
return [self.modules[RCTBridgeModuleNameForClass([RCTAssetsLibraryImageLoader class])] assetsLibrary];
|
||||
return [[self moduleForClass:[RCTAssetsLibraryImageLoader class]] assetsLibrary];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -32,16 +32,6 @@
|
|||
|
||||
RCT_EXPORT_MODULE(ImagePickerIOS);
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_pickers = [NSMutableArray new];
|
||||
_pickerCallbacks = [NSMutableArray new];
|
||||
_pickerCancelCallbacks = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return dispatch_get_main_queue();
|
||||
|
@ -67,8 +57,6 @@ RCT_EXPORT_METHOD(openCameraDialog:(NSDictionary *)config
|
|||
return;
|
||||
}
|
||||
|
||||
UIViewController *rootViewController = RCTKeyWindow().rootViewController;
|
||||
|
||||
UIImagePickerController *imagePicker = [UIImagePickerController new];
|
||||
imagePicker.delegate = self;
|
||||
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
|
||||
|
@ -77,11 +65,9 @@ RCT_EXPORT_METHOD(openCameraDialog:(NSDictionary *)config
|
|||
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
|
||||
}
|
||||
|
||||
[_pickers addObject:imagePicker];
|
||||
[_pickerCallbacks addObject:callback];
|
||||
[_pickerCancelCallbacks addObject:cancelCallback];
|
||||
|
||||
[rootViewController presentViewController:imagePicker animated:YES completion:nil];
|
||||
[self _presentPicker:imagePicker
|
||||
successCallback:callback
|
||||
cancelCallback:cancelCallback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(openSelectDialog:(NSDictionary *)config
|
||||
|
@ -93,8 +79,6 @@ RCT_EXPORT_METHOD(openSelectDialog:(NSDictionary *)config
|
|||
return;
|
||||
}
|
||||
|
||||
UIViewController *rootViewController = RCTKeyWindow().rootViewController;
|
||||
|
||||
UIImagePickerController *imagePicker = [UIImagePickerController new];
|
||||
imagePicker.delegate = self;
|
||||
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
|
||||
|
@ -109,30 +93,43 @@ RCT_EXPORT_METHOD(openSelectDialog:(NSDictionary *)config
|
|||
|
||||
imagePicker.mediaTypes = allowedTypes;
|
||||
|
||||
[_pickers addObject:imagePicker];
|
||||
[_pickerCallbacks addObject:callback];
|
||||
[_pickerCancelCallbacks addObject:cancelCallback];
|
||||
|
||||
[rootViewController presentViewController:imagePicker animated:YES completion:nil];
|
||||
[self _presentPicker:imagePicker
|
||||
successCallback:callback
|
||||
cancelCallback:cancelCallback];
|
||||
}
|
||||
|
||||
- (void)imagePickerController:(UIImagePickerController *)picker
|
||||
didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
|
||||
{
|
||||
NSUInteger index = [_pickers indexOfObject:picker];
|
||||
RCTResponseSenderBlock callback = _pickerCallbacks[index];
|
||||
|
||||
[_pickers removeObjectAtIndex:index];
|
||||
[_pickerCallbacks removeObjectAtIndex:index];
|
||||
[_pickerCancelCallbacks removeObjectAtIndex:index];
|
||||
|
||||
UIViewController *rootViewController = RCTKeyWindow().rootViewController;
|
||||
[rootViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
callback(@[[info[UIImagePickerControllerReferenceURL] absoluteString]]);
|
||||
[self _dismissPicker:picker args:@[
|
||||
[info[UIImagePickerControllerReferenceURL] absoluteString]
|
||||
]];
|
||||
}
|
||||
|
||||
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
|
||||
{
|
||||
[self _dismissPicker:picker args:nil];
|
||||
}
|
||||
|
||||
- (void)_presentPicker:(UIImagePickerController *)imagePicker
|
||||
successCallback:(RCTResponseSenderBlock)callback
|
||||
cancelCallback:(RCTResponseSenderBlock)cancelCallback
|
||||
{
|
||||
if (!_pickers) {
|
||||
_pickers = [NSMutableArray new];
|
||||
_pickerCallbacks = [NSMutableArray new];
|
||||
_pickerCancelCallbacks = [NSMutableArray new];
|
||||
}
|
||||
|
||||
[_pickers addObject:imagePicker];
|
||||
[_pickerCallbacks addObject:callback];
|
||||
[_pickerCancelCallbacks addObject:cancelCallback];
|
||||
|
||||
UIViewController *rootViewController = RCTKeyWindow().rootViewController;
|
||||
[rootViewController presentViewController:imagePicker animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)_dismissPicker:(UIImagePickerController *)picker args:(NSArray *)args
|
||||
{
|
||||
NSUInteger index = [_pickers indexOfObject:picker];
|
||||
RCTResponseSenderBlock callback = _pickerCancelCallbacks[index];
|
||||
|
@ -144,7 +141,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
|
|||
UIViewController *rootViewController = RCTKeyWindow().rootViewController;
|
||||
[rootViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
callback(@[]);
|
||||
callback(args ?: @[]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -111,19 +111,6 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
_locationManager = [CLLocationManager new];
|
||||
_locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
|
||||
_locationManager.delegate = self;
|
||||
|
||||
_pendingRequests = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_locationManager stopUpdatingLocation];
|
||||
|
@ -139,6 +126,13 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (void)beginLocationUpdates
|
||||
{
|
||||
if (!_locationManager) {
|
||||
_locationManager = [CLLocationManager new];
|
||||
_locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
|
||||
_locationManager.delegate = self;
|
||||
_pendingRequests = [NSMutableArray new];
|
||||
}
|
||||
|
||||
// Request location access permission
|
||||
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[_locationManager requestWhenInUseAuthorization];
|
||||
|
|
|
@ -45,17 +45,17 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
- (void)setUp
|
||||
{
|
||||
// Get image loaders and decoders
|
||||
NSMutableArray<id<RCTImageURLLoader>> *loaders = [NSMutableArray array];
|
||||
NSMutableArray<id<RCTImageDataDecoder>> *decoders = [NSMutableArray array];
|
||||
for (id<RCTBridgeModule> module in bridge.modules.allValues) {
|
||||
if ([module conformsToProtocol:@protocol(RCTImageURLLoader)]) {
|
||||
[loaders addObject:(id<RCTImageURLLoader>)module];
|
||||
for (Class moduleClass in _bridge.moduleClasses) {
|
||||
if ([moduleClass conformsToProtocol:@protocol(RCTImageURLLoader)]) {
|
||||
[loaders addObject:[_bridge moduleForClass:moduleClass]];
|
||||
}
|
||||
if ([module conformsToProtocol:@protocol(RCTImageDataDecoder)]) {
|
||||
[decoders addObject:(id<RCTImageDataDecoder>)module];
|
||||
if ([moduleClass conformsToProtocol:@protocol(RCTImageDataDecoder)]) {
|
||||
[decoders addObject:[_bridge moduleForClass:moduleClass]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,17 +85,16 @@ RCT_EXPORT_MODULE()
|
|||
}
|
||||
}];
|
||||
|
||||
_bridge = bridge;
|
||||
_loaders = loaders;
|
||||
_decoders = decoders;
|
||||
_URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
|
||||
_URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
|
||||
diskCapacity:200 * 1024 * 1024 // 200MB
|
||||
diskPath:@"React/RCTImageDownloader"];
|
||||
}
|
||||
|
||||
- (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
|
||||
{
|
||||
if (!_loaders) {
|
||||
[self setUp];
|
||||
}
|
||||
|
||||
if (RCT_DEBUG) {
|
||||
// Check for handler conflicts
|
||||
float previousPriority = 0;
|
||||
|
@ -133,6 +132,10 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (id<RCTImageDataDecoder>)imageDataDecoderForData:(NSData *)data
|
||||
{
|
||||
if (!_decoders) {
|
||||
[self setUp];
|
||||
}
|
||||
|
||||
if (RCT_DEBUG) {
|
||||
// Check for handler conflicts
|
||||
float previousPriority = 0;
|
||||
|
@ -212,7 +215,17 @@ RCT_EXPORT_MODULE()
|
|||
}
|
||||
|
||||
// All access to URL cache must be serialized
|
||||
if (!_URLCacheQueue) {
|
||||
_URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
dispatch_async(_URLCacheQueue, ^{
|
||||
|
||||
if (!_URLCache) {
|
||||
_URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
|
||||
diskCapacity:200 * 1024 * 1024 // 200MB
|
||||
diskPath:@"React/RCTImageDownloader"];
|
||||
}
|
||||
|
||||
RCTImageLoader *strongSelf = weakSelf;
|
||||
if (cancelled || !strongSelf) {
|
||||
return;
|
||||
|
@ -385,14 +398,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (BOOL)canHandleRequest:(NSURLRequest *)request
|
||||
{
|
||||
NSURL *requestURL = request.URL;
|
||||
for (id<RCTBridgeModule> module in _bridge.modules.allValues) {
|
||||
if ([module conformsToProtocol:@protocol(RCTImageURLLoader)] &&
|
||||
[(id<RCTImageURLLoader>)module canLoadImageURL:requestURL]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
return [self imageURLLoaderForURL:request.URL] != nil;
|
||||
}
|
||||
|
||||
- (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
|
||||
|
@ -440,7 +446,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (RCTImageLoader *)imageLoader
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTImageLoader class])];
|
||||
return [self moduleForClass:[RCTImageLoader class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -30,15 +30,6 @@ static NSString *const RCTImageStoreURLScheme = @"rct-image-store";
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_store = [NSMutableDictionary new];
|
||||
_id = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)removeImageForTag:(NSString *)imageTag withBlock:(void (^)())block
|
||||
{
|
||||
dispatch_async(_methodQueue, ^{
|
||||
|
@ -52,6 +43,12 @@ RCT_EXPORT_MODULE()
|
|||
- (NSString *)_storeImageData:(NSData *)imageData
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"Must be called on RCTImageStoreManager thread");
|
||||
|
||||
if (!_store) {
|
||||
_store = [NSMutableDictionary new];
|
||||
_id = 0;
|
||||
}
|
||||
|
||||
NSString *imageTag = [NSString stringWithFormat:@"%@://%tu", RCTImageStoreURLScheme, _id++];
|
||||
_store[imageTag] = imageData;
|
||||
return imageTag;
|
||||
|
@ -225,7 +222,7 @@ RCT_EXPORT_METHOD(addImageFromBase64:(NSString *)base64String
|
|||
|
||||
- (RCTImageStoreManager *)imageStoreManager
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTImageStoreManager class])];
|
||||
return [self moduleForClass:[RCTImageStoreManager class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -21,15 +21,20 @@ NSString *const RCTOpenURLNotification = @"RCTOpenURLNotification";
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleOpenURLNotification:)
|
||||
name:RCTOpenURLNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
_bridge = bridge;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleOpenURLNotification:)
|
||||
name:RCTOpenURLNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
NSURL *initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -75,10 +80,4 @@ RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
|
|||
callback(@[@(canOpen)]);
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
NSURL *initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -21,26 +21,16 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
|
||||
valueOptions:NSPointerFunctionsStrongMemory
|
||||
capacity:0];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
[_session invalidateAndCancel];
|
||||
_session = nil;
|
||||
_delegates = nil;
|
||||
}
|
||||
|
||||
- (BOOL)isValid
|
||||
{
|
||||
return _delegates != nil;
|
||||
// if session == nil and delegates != nil, we've been invalidated
|
||||
return _session || !_delegates;
|
||||
}
|
||||
|
||||
#pragma mark - NSURLRequestHandler
|
||||
|
@ -62,12 +52,17 @@ RCT_EXPORT_MODULE()
|
|||
{
|
||||
// Lazy setup
|
||||
if (!_session && [self isValid]) {
|
||||
|
||||
NSOperationQueue *callbackQueue = [NSOperationQueue new];
|
||||
callbackQueue.maxConcurrentOperationCount = 1;
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
_session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:self
|
||||
delegateQueue:callbackQueue];
|
||||
|
||||
_delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
|
||||
valueOptions:NSPointerFunctionsStrongMemory
|
||||
capacity:0];
|
||||
}
|
||||
|
||||
NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
|
||||
|
|
|
@ -130,36 +130,34 @@ static NSString *RCTGenerateFormBoundary()
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
// get handlers
|
||||
NSMutableArray<id<RCTURLRequestHandler>> *handlers = [NSMutableArray array];
|
||||
for (id<RCTBridgeModule> module in bridge.modules.allValues) {
|
||||
if ([module conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
|
||||
[handlers addObject:(id<RCTURLRequestHandler>)module];
|
||||
}
|
||||
}
|
||||
|
||||
// Sort handlers in reverse priority order (highest priority first)
|
||||
[handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
|
||||
float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
|
||||
float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
|
||||
if (priorityA > priorityB) {
|
||||
return NSOrderedAscending;
|
||||
} else if (priorityA < priorityB) {
|
||||
return NSOrderedDescending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
}];
|
||||
|
||||
_bridge = bridge;
|
||||
_handlers = handlers;
|
||||
_tasksByRequestID = [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
- (id<RCTURLRequestHandler>)handlerForRequest:(NSURLRequest *)request
|
||||
{
|
||||
if (!_handlers) {
|
||||
|
||||
// get handlers
|
||||
NSMutableArray<id<RCTURLRequestHandler>> *handlers = [NSMutableArray array];
|
||||
for (Class moduleClass in _bridge.moduleClasses) {
|
||||
if ([moduleClass conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
|
||||
[handlers addObject:[_bridge moduleForClass:moduleClass]];
|
||||
}
|
||||
}
|
||||
|
||||
// Sort handlers in reverse priority order (highest priority first)
|
||||
[handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
|
||||
float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
|
||||
float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
|
||||
if (priorityA > priorityB) {
|
||||
return NSOrderedAscending;
|
||||
} else if (priorityA < priorityB) {
|
||||
return NSOrderedDescending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
}];
|
||||
|
||||
_handlers = handlers;
|
||||
}
|
||||
|
||||
if (RCT_DEBUG) {
|
||||
// Check for handler conflicts
|
||||
float previousPriority = 0;
|
||||
|
@ -198,6 +196,8 @@ RCT_EXPORT_MODULE()
|
|||
- (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary<NSString *, id> *)query
|
||||
completionBlock:(void (^)(NSURLRequest *request))block
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"buildRequest: must be called on method queue");
|
||||
|
||||
NSURL *URL = [RCTConvert NSURL:query[@"url"]]; // this is marked as nullable in JS, but should not be null
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
|
||||
request.HTTPMethod = [RCTConvert NSString:RCTNilIfNull(query[@"method"])].uppercaseString ?: @"GET";
|
||||
|
@ -222,7 +222,10 @@ RCT_EXPORT_MODULE()
|
|||
[request setValue:(@(request.HTTPBody.length)).description forHTTPHeaderField:@"Content-Length"];
|
||||
}
|
||||
|
||||
block(request);
|
||||
dispatch_async(_methodQueue, ^{
|
||||
block(request);
|
||||
});
|
||||
|
||||
return (RCTURLRequestCancellationBlock)nil;
|
||||
}];
|
||||
}
|
||||
|
@ -253,6 +256,8 @@ RCT_EXPORT_MODULE()
|
|||
- (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary<NSString *, id> *)query callback:
|
||||
(RCTURLRequestCancellationBlock (^)(NSError *error, NSDictionary<NSString *, id> *result))callback
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"processData: must be called on method queue");
|
||||
|
||||
if (!query) {
|
||||
return callback(nil, nil);
|
||||
}
|
||||
|
@ -291,6 +296,8 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (void)sendData:(NSData *)data forTask:(RCTNetworkTask *)task
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"sendData: must be called on method queue");
|
||||
|
||||
if (data.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -335,6 +342,8 @@ RCT_EXPORT_MODULE()
|
|||
incrementalUpdates:(BOOL)incrementalUpdates
|
||||
responseSender:(RCTResponseSenderBlock)responseSender
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"sendRequest: must be called on method queue");
|
||||
|
||||
__block RCTNetworkTask *task;
|
||||
|
||||
RCTURLRequestProgressBlock uploadProgressBlock = ^(int64_t progress, int64_t total) {
|
||||
|
@ -391,6 +400,9 @@ RCT_EXPORT_MODULE()
|
|||
task.uploadProgressBlock = uploadProgressBlock;
|
||||
|
||||
if (task.requestID) {
|
||||
if (_tasksByRequestID) {
|
||||
_tasksByRequestID = [NSMutableDictionary new];
|
||||
}
|
||||
_tasksByRequestID[task.requestID] = task;
|
||||
responseSender(@[task.requestID]);
|
||||
}
|
||||
|
@ -443,7 +455,7 @@ RCT_EXPORT_METHOD(cancelRequest:(nonnull NSNumber *)requestID)
|
|||
|
||||
- (RCTNetworking *)networking
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTNetworking class])];
|
||||
return [self moduleForClass:[RCTNetworking class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -41,29 +41,11 @@ NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegister
|
|||
@end
|
||||
|
||||
@implementation RCTPushNotificationManager
|
||||
{
|
||||
NSDictionary<NSString *, id> *_initialNotification;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleRemoteNotificationReceived:)
|
||||
name:RCTRemoteNotificationReceived
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleRemoteNotificationsRegistered:)
|
||||
name:RCTRemoteNotificationsRegistered
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
@ -72,7 +54,21 @@ RCT_EXPORT_MODULE()
|
|||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
_initialNotification = [bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleRemoteNotificationReceived:)
|
||||
name:RCTRemoteNotificationReceived
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleRemoteNotificationsRegistered:)
|
||||
name:RCTRemoteNotificationsRegistered
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
NSDictionary<NSString *, id> *initialNotification = [_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
|
||||
return @{@"initialNotification": RCTNullIfNil(initialNotification)};
|
||||
}
|
||||
|
||||
+ (void)application:(__unused UIApplication *)application didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
|
||||
|
@ -200,13 +196,6 @@ RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
|
|||
callback(@[permissions]);
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
return @{
|
||||
@"initialNotification": RCTNullIfNil(_initialNotification),
|
||||
};
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
|
||||
{
|
||||
[RCTSharedApplication() presentLocalNotificationNow:notification];
|
||||
|
|
|
@ -29,14 +29,6 @@ RCT_EXPORT_MODULE()
|
|||
return _bridge.uiManager.methodQueue;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_snapshotCounter = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
RCTAssert(_controller != nil, @"No snapshot controller configured.");
|
||||
|
@ -44,6 +36,9 @@ RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback)
|
|||
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
|
||||
NSString *testName = NSStringFromSelector(_testSelector);
|
||||
if (!_snapshotCounter) {
|
||||
_snapshotCounter = [NSMutableDictionary new];
|
||||
}
|
||||
_snapshotCounter[testName] = (@([_snapshotCounter[testName] integerValue] + 1)).stringValue;
|
||||
|
||||
NSError *error = nil;
|
||||
|
|
|
@ -112,8 +112,7 @@ expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock
|
|||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps];
|
||||
rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices
|
||||
|
||||
NSString *testModuleName = RCTBridgeModuleNameForClass([RCTTestModule class]);
|
||||
RCTTestModule *testModule = rootView.bridge.modules[testModuleName];
|
||||
RCTTestModule *testModule = [rootView.bridge moduleForClass:[RCTTestModule class]];
|
||||
RCTAssert(_testController != nil, @"_testController should not be nil");
|
||||
testModule.controller = _testController;
|
||||
testModule.testSelector = test;
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
|
||||
@interface RCTSettingsManager : NSObject <RCTBridgeModule>
|
||||
|
||||
- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults;
|
||||
|
||||
@end
|
||||
|
|
|
@ -24,23 +24,31 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
if ((self = [self init])) {
|
||||
_defaults = defaults;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(userDefaultsDidChange:)
|
||||
name:NSUserDefaultsDidChangeNotification
|
||||
object:_defaults];
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
|
||||
if (!_defaults) {
|
||||
_defaults = [NSUserDefaults standardUserDefaults];
|
||||
}
|
||||
|
||||
return self;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(userDefaultsDidChange:)
|
||||
name:NSUserDefaultsDidChangeNotification
|
||||
object:_defaults];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
return @{@"settings": RCTJSONClean([_defaults dictionaryRepresentation])};
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -59,13 +67,6 @@ RCT_EXPORT_MODULE()
|
|||
body:RCTJSONClean([_defaults dictionaryRepresentation])];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
return @{
|
||||
@"settings": RCTJSONClean([_defaults dictionaryRepresentation])
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more values in the settings.
|
||||
* TODO: would it be useful to have a callback for when this has completed?
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
@interface RCTWebSocketExecutor : NSObject <RCTJavaScriptExecutor>
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)URL NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithURL:(NSURL *)URL;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -36,19 +36,11 @@ typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary<NSString *, id
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
|
||||
NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
|
||||
NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
|
||||
return [self initWithURL:[RCTConvert NSURL:URLString]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)URL
|
||||
{
|
||||
RCTAssertParam(URL);
|
||||
|
||||
if ((self = [super init])) {
|
||||
if ((self = [self init])) {
|
||||
_url = URL;
|
||||
}
|
||||
return self;
|
||||
|
@ -56,6 +48,13 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (void)setUp
|
||||
{
|
||||
if (!_url) {
|
||||
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
|
||||
NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
|
||||
NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
|
||||
_url = [RCTConvert NSURL:URLString];
|
||||
}
|
||||
|
||||
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
|
||||
_socket = [[RCTSRWebSocket alloc] initWithURL:_url];
|
||||
_socket.delegate = self;
|
||||
|
@ -193,11 +192,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
|
||||
{
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
RCTExecuteOnMainThread(block, NO);
|
||||
}
|
||||
|
||||
- (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block
|
||||
|
|
|
@ -41,14 +41,6 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_sockets = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
for (RCTSRWebSocket *socket in _sockets.allValues) {
|
||||
|
@ -62,6 +54,9 @@ RCT_EXPORT_METHOD(connect:(NSURL *)URL socketID:(nonnull NSNumber *)socketID)
|
|||
RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL];
|
||||
webSocket.delegate = self;
|
||||
webSocket.reactTag = socketID;
|
||||
if (!_sockets) {
|
||||
_sockets = [NSMutableDictionary new];
|
||||
}
|
||||
_sockets[socketID] = webSocket;
|
||||
[webSocket open];
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#import "RCTJavaScriptLoader.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTModuleData.h"
|
||||
#import "RCTModuleMap.h"
|
||||
#import "RCTPerformanceLogger.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTSourceCode.h"
|
||||
|
@ -48,6 +47,8 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
+ (instancetype)currentBridge;
|
||||
+ (void)setCurrentBridge:(RCTBridge *)bridge;
|
||||
|
||||
@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBatchedBridge : RCTBridge
|
||||
|
@ -63,10 +64,16 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
BOOL _wasBatchActive;
|
||||
__weak id<RCTJavaScriptExecutor> _javaScriptExecutor;
|
||||
NSMutableArray<NSArray *> *_pendingCalls;
|
||||
NSMutableArray<RCTModuleData *> *_moduleDataByID;
|
||||
RCTModuleMap *_modulesByName;
|
||||
NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
|
||||
NSArray<RCTModuleData *> *_moduleDataByID;
|
||||
NSDictionary<NSString *, id<RCTBridgeModule>> *_modulesByName_DEPRECATED;
|
||||
NSArray<Class> *_moduleClassesByID;
|
||||
CADisplayLink *_jsDisplayLink;
|
||||
NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
|
||||
|
||||
// Bridge startup stats (TODO: capture in perf logger)
|
||||
NSUInteger _syncInitializedModules;
|
||||
NSUInteger _asyncInitializedModules;
|
||||
}
|
||||
|
||||
- (instancetype)initWithParentBridge:(RCTBridge *)bridge
|
||||
|
@ -86,7 +93,6 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
_valid = YES;
|
||||
_loading = YES;
|
||||
_pendingCalls = [NSMutableArray new];
|
||||
_moduleDataByID = [NSMutableArray new];
|
||||
_frameUpdateObservers = [NSMutableSet new];
|
||||
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
||||
|
||||
|
@ -106,6 +112,8 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
dispatch_queue_t bridgeQueue = dispatch_queue_create("com.facebook.react.RCTBridgeQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
dispatch_group_t initModulesAndLoadSource = dispatch_group_create();
|
||||
|
||||
// Asynchronously load source code
|
||||
dispatch_group_enter(initModulesAndLoadSource);
|
||||
__weak RCTBatchedBridge *weakSelf = self;
|
||||
__block NSData *sourceCode;
|
||||
|
@ -120,9 +128,13 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
dispatch_group_leave(initModulesAndLoadSource);
|
||||
}];
|
||||
|
||||
// Synchronously initialize all native modules
|
||||
// Synchronously initialize all native modules that cannot be deferred
|
||||
[self initModules];
|
||||
|
||||
#if RCT_DEBUG
|
||||
_syncInitializedModules = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
|
||||
#endif
|
||||
|
||||
if (RCTProfileIsProfiling()) {
|
||||
// Depends on moduleDataByID being loaded
|
||||
RCTProfileHookModules(self);
|
||||
|
@ -132,22 +144,32 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
dispatch_group_enter(initModulesAndLoadSource);
|
||||
dispatch_async(bridgeQueue, ^{
|
||||
dispatch_group_t setupJSExecutorAndModuleConfig = dispatch_group_create();
|
||||
|
||||
// Asynchronously initialize the JS executor
|
||||
dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
|
||||
[weakSelf setupExecutor];
|
||||
[weakSelf setUpExecutor];
|
||||
});
|
||||
|
||||
// Asynchronously gather the module config
|
||||
dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
|
||||
if (weakSelf.isValid) {
|
||||
|
||||
RCTPerformanceLoggerStart(RCTPLNativeModulePrepareConfig);
|
||||
config = [weakSelf moduleConfig];
|
||||
RCTPerformanceLoggerEnd(RCTPLNativeModulePrepareConfig);
|
||||
|
||||
#if RCT_DEBUG
|
||||
NSInteger total = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
|
||||
_asyncInitializedModules = total - _syncInitializedModules;
|
||||
#endif
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_group_notify(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
|
||||
// We're not waiting for this complete to leave the dispatch group, since
|
||||
// injectJSONConfiguration and executeSourceCode will schedule operations on the
|
||||
// same queue anyway.
|
||||
// We're not waiting for this to complete to leave dispatch group, since
|
||||
// injectJSONConfiguration and executeSourceCode will schedule operations
|
||||
// on the same queue anyway.
|
||||
RCTPerformanceLoggerStart(RCTPLNativeModuleInjectConfig);
|
||||
[weakSelf injectJSONConfiguration:config onComplete:^(NSError *error) {
|
||||
RCTPerformanceLoggerEnd(RCTPLNativeModuleInjectConfig);
|
||||
|
@ -199,6 +221,28 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
}
|
||||
}
|
||||
|
||||
- (NSArray<Class> *)moduleClasses
|
||||
{
|
||||
if (RCT_DEBUG && self.isValid && _moduleClassesByID == nil) {
|
||||
RCTLogError(@"Bridge modules have not yet been initialized. You may be "
|
||||
"trying to access a module too early in the startup procedure.");
|
||||
}
|
||||
return _moduleClassesByID;
|
||||
}
|
||||
|
||||
- (id)moduleForName:(NSString *)moduleName
|
||||
{
|
||||
RCTModuleData *moduleData = _moduleDataByName[moduleName];
|
||||
if (RCT_DEBUG) {
|
||||
Class moduleClass = moduleData.moduleClass;
|
||||
if (!RCTBridgeModuleClassIsRegistered(moduleClass)) {
|
||||
RCTLogError(@"Class %@ was not exported. Did you forget to use "
|
||||
"RCT_EXPORT_MODULE()?", moduleClass);
|
||||
}
|
||||
}
|
||||
return moduleData.instance;
|
||||
}
|
||||
|
||||
- (void)initModules
|
||||
{
|
||||
RCTAssertMainThread();
|
||||
|
@ -220,54 +264,71 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
preregisteredModules[RCTBridgeModuleNameForClass([module class])] = module;
|
||||
}
|
||||
|
||||
// Instantiate modules
|
||||
_moduleDataByID = [NSMutableArray new];
|
||||
NSMutableDictionary *modulesByName = [preregisteredModules mutableCopy];
|
||||
SEL setBridgeSelector = NSSelectorFromString(@"setBridge:");
|
||||
IMP objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
|
||||
|
||||
// Set up moduleData and pre-initialize module instances
|
||||
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
|
||||
for (Class moduleClass in RCTGetModuleClasses()) {
|
||||
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
|
||||
id module = preregisteredModules[moduleName];
|
||||
if (!module) {
|
||||
// Check if the module class, or any of its superclasses override init
|
||||
// or setBridge:. If they do, we assume that they are expecting to be
|
||||
// initialized when the bridge first loads.
|
||||
if ([moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod ||
|
||||
[moduleClass instancesRespondToSelector:setBridgeSelector]) {
|
||||
module = [moduleClass new];
|
||||
if (!module) {
|
||||
module = [NSNull null];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if module instance has already been registered for this name
|
||||
id<RCTBridgeModule> module = modulesByName[moduleName];
|
||||
// Check for module name collisions.
|
||||
// It's OK to have a name collision as long as the second instance is null.
|
||||
if (module != [NSNull class] && _moduleDataByName[moduleName]) {
|
||||
RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the name "
|
||||
"'%@', but name was already registered by class %@", moduleClass,
|
||||
moduleName, _moduleDataByName[moduleName]);
|
||||
}
|
||||
|
||||
if (module) {
|
||||
// Preregistered instances takes precedence, no questions asked
|
||||
if (!preregisteredModules[moduleName]) {
|
||||
// It's OK to have a name collision as long as the second instance is nil
|
||||
RCTAssert([moduleClass new] == nil,
|
||||
@"Attempted to register RCTBridgeModule class %@ for the name "
|
||||
"'%@', but name was already registered by class %@", moduleClass,
|
||||
moduleName, [modulesByName[moduleName] class]);
|
||||
}
|
||||
} else {
|
||||
// Module name hasn't been used before, so go ahead and instantiate
|
||||
module = [moduleClass new];
|
||||
}
|
||||
if (module) {
|
||||
modulesByName[moduleName] = module;
|
||||
}
|
||||
// Instantiate moduleData (TODO: defer this until config generation)
|
||||
RCTModuleData *moduleData;
|
||||
if (module) {
|
||||
if (module != [NSNull null]) {
|
||||
moduleData = [[RCTModuleData alloc] initWithModuleInstance:module];
|
||||
}
|
||||
} else {
|
||||
moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
|
||||
bridge:self];
|
||||
}
|
||||
if (moduleData) {
|
||||
moduleDataByName[moduleName] = moduleData;
|
||||
[moduleDataByID addObject:moduleData];
|
||||
}
|
||||
}
|
||||
|
||||
// Store modules
|
||||
_modulesByName = [[RCTModuleMap alloc] initWithDictionary:modulesByName];
|
||||
_moduleDataByID = [moduleDataByID copy];
|
||||
_moduleDataByName = [moduleDataByName copy];
|
||||
_moduleClassesByID = [moduleDataByID valueForKey:@"moduleClass"];
|
||||
|
||||
/**
|
||||
* The executor is a bridge module, wait for it to be created and set it before
|
||||
* any other module has access to the bridge
|
||||
*/
|
||||
_javaScriptExecutor = _modulesByName[RCTBridgeModuleNameForClass(self.executorClass)];
|
||||
_javaScriptExecutor = [self moduleForClass:self.executorClass];
|
||||
|
||||
for (id<RCTBridgeModule> module in _modulesByName.allValues) {
|
||||
// Bridge must be set before moduleData is set up, as methodQueue
|
||||
// initialization requires it (View Managers get their queue by calling
|
||||
// self.bridge.uiManager.methodQueue)
|
||||
if ([module respondsToSelector:@selector(setBridge:)]) {
|
||||
module.bridge = self;
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
[moduleData setBridgeForInstance:self];
|
||||
}
|
||||
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
if (moduleData.hasInstance) {
|
||||
[moduleData methodQueue]; // initialize the queue
|
||||
}
|
||||
|
||||
RCTModuleData *moduleData = [[RCTModuleData alloc] initWithExecutor:_javaScriptExecutor
|
||||
moduleID:@(_moduleDataByID.count)
|
||||
instance:module];
|
||||
[_moduleDataByID addObject:moduleData];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTDidCreateNativeModules
|
||||
|
@ -275,7 +336,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
RCTPerformanceLoggerEnd(RCTPLNativeModuleInit);
|
||||
}
|
||||
|
||||
- (void)setupExecutor
|
||||
- (void)setUpExecutor
|
||||
{
|
||||
[_javaScriptExecutor setUp];
|
||||
}
|
||||
|
@ -284,8 +345,8 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
{
|
||||
NSMutableArray<NSArray *> *config = [NSMutableArray new];
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
[config addObject:moduleData.config];
|
||||
if ([moduleData.instance conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
|
||||
[config addObject:RCTNullIfNil(moduleData.config)];
|
||||
if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
|
||||
[_frameUpdateObservers addObject:moduleData];
|
||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
@ -336,7 +397,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
return;
|
||||
}
|
||||
|
||||
RCTSourceCode *sourceCodeModule = self.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
|
||||
RCTSourceCode *sourceCodeModule = [self moduleForClass:[RCTSourceCode class]];
|
||||
sourceCodeModule.scriptURL = self.bundleURL;
|
||||
sourceCodeModule.scriptData = sourceCode;
|
||||
|
||||
|
@ -448,13 +509,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
return _valid;
|
||||
}
|
||||
|
||||
- (NSDictionary *)modules
|
||||
- (void)dispatchBlock:(dispatch_block_t)block
|
||||
queue:(dispatch_queue_t)queue
|
||||
{
|
||||
if (RCT_DEBUG && self.isValid && _modulesByName == nil) {
|
||||
RCTLogError(@"Bridge modules have not yet been initialized. You may be "
|
||||
"trying to access a module too early in the startup procedure.");
|
||||
if (queue == RCTJSThread) {
|
||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
|
||||
} else if (queue) {
|
||||
dispatch_async(queue, block);
|
||||
}
|
||||
return _modulesByName;
|
||||
}
|
||||
|
||||
#pragma mark - RCTInvalidating
|
||||
|
@ -475,17 +537,19 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
|
||||
// Invalidate modules
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
for (RCTModuleData *moduleData in _moduleDataByName.allValues) {
|
||||
if (moduleData.instance == _javaScriptExecutor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([moduleData.instance respondsToSelector:@selector(invalidate)]) {
|
||||
[moduleData dispatchBlock:^{
|
||||
dispatch_group_enter(group);
|
||||
[self dispatchBlock:^{
|
||||
[(id<RCTInvalidating>)moduleData.instance invalidate];
|
||||
} dispatchGroup:group];
|
||||
dispatch_group_leave(group);
|
||||
} queue:moduleData.methodQueue];
|
||||
}
|
||||
moduleData.queue = nil;
|
||||
[moduleData invalidate];
|
||||
}
|
||||
|
||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
|
@ -499,8 +563,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
if (RCTProfileIsProfiling()) {
|
||||
RCTProfileUnhookModules(self);
|
||||
}
|
||||
_moduleDataByName = nil;
|
||||
_moduleDataByID = nil;
|
||||
_modulesByName = nil;
|
||||
_moduleClassesByID = nil;
|
||||
_modulesByName_DEPRECATED = nil;
|
||||
_frameUpdateObservers = nil;
|
||||
|
||||
}];
|
||||
|
@ -683,15 +749,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
|
||||
NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
|
||||
valueOptions:NSPointerFunctionsStrongMemory
|
||||
capacity:_moduleDataByID.count];
|
||||
capacity:_moduleDataByName.count];
|
||||
|
||||
[moduleIDs enumerateObjectsUsingBlock:^(NSNumber *moduleID, NSUInteger i, __unused BOOL *stop) {
|
||||
RCTModuleData *moduleData = _moduleDataByID[moduleID.integerValue];
|
||||
if (RCT_DEBUG) {
|
||||
// verify that class has been registered
|
||||
(void)_modulesByName[moduleData.name];
|
||||
}
|
||||
dispatch_queue_t queue = moduleData.queue;
|
||||
dispatch_queue_t queue = moduleData.methodQueue;
|
||||
NSMutableOrderedSet<NSNumber *> *set = [buckets objectForKey:queue];
|
||||
if (!set) {
|
||||
set = [NSMutableOrderedSet new];
|
||||
|
@ -739,10 +801,10 @@ 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.instance respondsToSelector:@selector(batchDidComplete)]) {
|
||||
[moduleData dispatchBlock:^{
|
||||
if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(batchDidComplete)]) {
|
||||
[self dispatchBlock:^{
|
||||
[moduleData.instance batchDidComplete];
|
||||
}];
|
||||
} queue:moduleData.methodQueue];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -812,12 +874,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];)
|
||||
RCTProfileBeginFlowEvent();
|
||||
|
||||
[moduleData dispatchBlock:^{
|
||||
[self dispatchBlock:^{
|
||||
RCTProfileEndFlowEvent();
|
||||
RCT_PROFILE_BEGIN_EVENT(0, name, nil);
|
||||
[observer didUpdateFrame:frameUpdate];
|
||||
RCT_PROFILE_END_EVENT(0, @"objc_call,fps", nil);
|
||||
}];
|
||||
} queue:moduleData.methodQueue];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -851,3 +913,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTBatchedBridge(Deprecated)
|
||||
|
||||
- (NSDictionary *)modules
|
||||
{
|
||||
if (!_modulesByName_DEPRECATED) {
|
||||
// Check classes are set up
|
||||
[self moduleClasses];
|
||||
NSMutableDictionary *modulesByName = [NSMutableDictionary new];
|
||||
for (NSString *moduleName in _moduleDataByName) {
|
||||
id module = [self moduleForName:moduleName];
|
||||
if (module) {
|
||||
modulesByName[moduleName] = module;
|
||||
}
|
||||
};
|
||||
_modulesByName_DEPRECATED = [modulesByName copy];
|
||||
}
|
||||
return _modulesByName_DEPRECATED;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,6 +37,7 @@ NSString *const RCTDidCreateNativeModules = @"RCTDidCreateNativeModules";
|
|||
@interface RCTBridge ()
|
||||
|
||||
@property (nonatomic, strong) RCTBatchedBridge *batchedBridge;
|
||||
@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -87,9 +88,8 @@ NSString *RCTBridgeModuleNameForClass(Class cls)
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if class has been registered
|
||||
* This function checks if a class has been registered
|
||||
*/
|
||||
BOOL RCTBridgeModuleClassIsRegistered(Class);
|
||||
BOOL RCTBridgeModuleClassIsRegistered(Class cls)
|
||||
{
|
||||
return [objc_getAssociatedObject(cls, &RCTBridgeModuleClassIsRegistered) ?: @YES boolValue];
|
||||
|
@ -230,9 +230,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
#endif
|
||||
}
|
||||
|
||||
- (NSArray<Class> *)moduleClasses
|
||||
{
|
||||
return _batchedBridge.moduleClasses;
|
||||
}
|
||||
|
||||
- (id)moduleForName:(NSString *)moduleName
|
||||
{
|
||||
return [_batchedBridge moduleForName:moduleName];
|
||||
}
|
||||
|
||||
- (id)moduleForClass:(Class)moduleClass
|
||||
{
|
||||
return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
|
||||
}
|
||||
|
||||
- (RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTEventDispatcher class])];
|
||||
return [self moduleForClass:[RCTEventDispatcher class]];
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
|
@ -281,10 +296,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
[_batchedBridge logMessage:message level:level];
|
||||
}
|
||||
|
||||
- (NSDictionary *)modules
|
||||
{
|
||||
return _batchedBridge.modules;
|
||||
}
|
||||
|
||||
#define RCT_INNER_BRIDGE_ONLY(...) \
|
||||
- (void)__VA_ARGS__ \
|
||||
|
@ -303,3 +314,12 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
|
|||
method:(__unused NSString *)method
|
||||
arguments:(__unused NSArray *)args);
|
||||
@end
|
||||
|
||||
@implementation RCTBridge(Deprecated)
|
||||
|
||||
- (NSDictionary *)modules
|
||||
{
|
||||
return _batchedBridge.modules;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -76,7 +76,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \
|
|||
* will be set automatically by the bridge when it initializes the module.
|
||||
* To implement this in your module, just add `@synthesize bridge = _bridge;`
|
||||
*/
|
||||
@property (nonatomic, weak) RCTBridge *bridge;
|
||||
@property (nonatomic, weak, readonly) RCTBridge *bridge;
|
||||
|
||||
/**
|
||||
* The queue that will be used to call all exported methods. If omitted, this
|
||||
|
|
|
@ -97,14 +97,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_paused = YES;
|
||||
_eventQueue = [NSMutableDictionary new];
|
||||
_eventQueueLock = [NSLock new];
|
||||
}
|
||||
return self;
|
||||
_bridge = bridge;
|
||||
_paused = YES;
|
||||
_eventQueue = [NSMutableDictionary new];
|
||||
_eventQueueLock = [NSLock new];
|
||||
}
|
||||
|
||||
- (void)setPaused:(BOOL)paused
|
||||
|
|
|
@ -19,25 +19,24 @@ static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification);
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
_bridge = bridge;
|
||||
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
|
||||
#define ADD_KEYBOARD_HANDLER(NAME, SELECTOR) \
|
||||
[nc addObserver:self selector:@selector(SELECTOR:) name:NAME object:nil]
|
||||
[nc addObserver:self selector:@selector(SELECTOR:) name:NAME object:nil]
|
||||
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillShowNotification, keyboardWillShow);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidShowNotification, keyboardDidShow);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillHideNotification, keyboardWillHide);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidHideNotification, keyboardDidHide);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillChangeFrameNotification, keyboardWillChangeFrame);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidChangeFrameNotification, keyboardDidChangeFrame);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillShowNotification, keyboardWillShow);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidShowNotification, keyboardDidShow);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillHideNotification, keyboardWillHide);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidHideNotification, keyboardDidHide);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardWillChangeFrameNotification, keyboardWillChangeFrame);
|
||||
ADD_KEYBOARD_HANDLER(UIKeyboardDidChangeFrameNotification, keyboardDidChangeFrame);
|
||||
|
||||
#undef ADD_KEYBOARD_HANDLER
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
|
|
@ -9,28 +9,58 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RCTJavaScriptExecutor.h"
|
||||
#import "RCTInvalidating.h"
|
||||
|
||||
@protocol RCTBridgeMethod;
|
||||
@protocol RCTBridgeModule;
|
||||
@class RCTBridge;
|
||||
|
||||
@interface RCTModuleData : NSObject
|
||||
@interface RCTModuleData : NSObject <RCTInvalidating>
|
||||
|
||||
@property (nonatomic, weak, readonly) id<RCTJavaScriptExecutor> javaScriptExecutor;
|
||||
@property (nonatomic, strong, readonly) NSNumber *moduleID;
|
||||
@property (nonatomic, strong, readonly) id<RCTBridgeModule> instance;
|
||||
- (instancetype)initWithModuleClass:(Class)moduleClass
|
||||
bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Sets the bridge for the module instance. This is only needed when using the
|
||||
* `initWithModuleID:instance:` constructor. Otherwise, the bridge will be set
|
||||
* automatically when the module is first accessed.
|
||||
*/
|
||||
- (void)setBridgeForInstance:(RCTBridge *)bridge;
|
||||
|
||||
@property (nonatomic, strong, readonly) Class moduleClass;
|
||||
@property (nonatomic, copy, readonly) NSString *name;
|
||||
|
||||
/**
|
||||
* Returns the module methods. Note that this will gather the methods the first
|
||||
* time it is called and then memoize the results.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSArray<id<RCTBridgeMethod>> *methods;
|
||||
|
||||
/**
|
||||
* Returns YES if module instance has already been initialized; NO otherwise.
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) BOOL hasInstance;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* without causing it to be created, use `hasInstance` instead.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) id<RCTBridgeModule> instance;
|
||||
|
||||
/**
|
||||
* Returns the module method dispatch queue. Note that this will init both the
|
||||
* queue and the module itself if they have not already been created.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) dispatch_queue_t methodQueue;
|
||||
|
||||
/**
|
||||
* Returns the module config. Note that this will init the module if it has
|
||||
* not already been created. This method can be called on any thread, but will
|
||||
* block the main thread briefly if the module implements `constantsToExport`.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSArray *config;
|
||||
|
||||
@property (nonatomic, strong) dispatch_queue_t queue;
|
||||
|
||||
- (instancetype)initWithExecutor:(id<RCTJavaScriptExecutor>)javaScriptExecutor
|
||||
moduleID:(NSNumber *)moduleID
|
||||
instance:(id<RCTBridgeModule>)instance NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)dispatchBlock:(dispatch_block_t)block;
|
||||
- (void)dispatchBlock:(dispatch_block_t)block dispatchGroup:(dispatch_group_t)group;
|
||||
|
||||
@end
|
||||
|
|
|
@ -16,37 +16,75 @@
|
|||
|
||||
@implementation RCTModuleData
|
||||
{
|
||||
NSDictionary *_constants;
|
||||
NSString *_queueName;
|
||||
__weak RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
@synthesize methods = _methods;
|
||||
@synthesize instance = _instance;
|
||||
@synthesize methodQueue = _methodQueue;
|
||||
|
||||
- (instancetype)initWithExecutor:(id<RCTJavaScriptExecutor>)javaScriptExecutor
|
||||
moduleID:(NSNumber *)moduleID
|
||||
instance:(id<RCTBridgeModule>)instance
|
||||
- (instancetype)initWithModuleClass:(Class)moduleClass
|
||||
bridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_moduleClass = moduleClass;
|
||||
_bridge = bridge;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_javaScriptExecutor = javaScriptExecutor;
|
||||
_moduleID = moduleID;
|
||||
_instance = instance;
|
||||
_moduleClass = [instance class];
|
||||
_name = RCTBridgeModuleNameForClass(_moduleClass);
|
||||
|
||||
// Must be done at init time to ensure it's called on main thread
|
||||
RCTAssertMainThread();
|
||||
if ([_instance respondsToSelector:@selector(constantsToExport)]) {
|
||||
_constants = [_instance constantsToExport];
|
||||
}
|
||||
|
||||
// Must be done at init time due to race conditions
|
||||
(void)self.queue;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
||||
|
||||
- (BOOL)hasInstance
|
||||
{
|
||||
return _instance != nil;
|
||||
}
|
||||
|
||||
- (id<RCTBridgeModule>)instance
|
||||
{
|
||||
if (!_instance) {
|
||||
_instance = [_moduleClass new];
|
||||
|
||||
// Bridge must be set before methodQueue is set up, as methodQueue
|
||||
// initialization requires it (View Managers get their queue by calling
|
||||
// self.bridge.uiManager.methodQueue)
|
||||
[self setBridgeForInstance:_bridge];
|
||||
|
||||
// Initialize queue
|
||||
[self methodQueue];
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
- (void)setBridgeForInstance:(RCTBridge *)bridge
|
||||
{
|
||||
if ([_instance respondsToSelector:@selector(bridge)]) {
|
||||
@try {
|
||||
[(id)_instance setValue:bridge forKey:@"bridge"];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
RCTLogError(@"%@ has no setter or ivar for its bridge, which is not "
|
||||
"permitted. You must either @synthesize the bridge property, "
|
||||
"or provide your own setter method.", self.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return RCTBridgeModuleNameForClass(_moduleClass);
|
||||
}
|
||||
|
||||
- (NSArray<id<RCTBridgeMethod>> *)methods
|
||||
{
|
||||
if (!_methods) {
|
||||
|
@ -84,7 +122,15 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
|
||||
- (NSArray *)config
|
||||
{
|
||||
if (_constants.count == 0 && self.methods.count == 0) {
|
||||
__block NSDictionary<NSString *, id> *constants;
|
||||
if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
|
||||
[self instance]; // Initialize instance
|
||||
RCTExecuteOnMainThread(^{
|
||||
constants = [_instance constantsToExport];
|
||||
}, YES);
|
||||
}
|
||||
|
||||
if (constants.count == 0 && self.methods.count == 0) {
|
||||
return (id)kCFNull; // Nothing to export
|
||||
}
|
||||
|
||||
|
@ -101,9 +147,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
}
|
||||
|
||||
NSMutableArray *config = [NSMutableArray new];
|
||||
[config addObject:_name];
|
||||
if (_constants.count) {
|
||||
[config addObject:_constants];
|
||||
[config addObject:self.name];
|
||||
if (constants.count) {
|
||||
[config addObject:constants];
|
||||
}
|
||||
if (methods) {
|
||||
[config addObject:methods];
|
||||
|
@ -114,53 +160,39 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
|||
return config;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)queue
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
if (!_queue) {
|
||||
BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
|
||||
if (!_methodQueue) {
|
||||
BOOL implementsMethodQueue = [self.instance respondsToSelector:@selector(methodQueue)];
|
||||
if (implementsMethodQueue) {
|
||||
_queue = _instance.methodQueue;
|
||||
_methodQueue = _instance.methodQueue;
|
||||
}
|
||||
if (!_queue) {
|
||||
if (!_methodQueue) {
|
||||
|
||||
// Create new queue (store queueName, as it isn't retained by dispatch_queue)
|
||||
_queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", _name];
|
||||
_queue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
|
||||
_queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
|
||||
_methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
// assign it to the module
|
||||
if (implementsMethodQueue) {
|
||||
@try {
|
||||
[(id)_instance setValue:_queue forKey:@"methodQueue"];
|
||||
[(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
|
||||
"permitted. You must either return a pre-initialized "
|
||||
"queue, or @synthesize the methodQueue to let the bridge "
|
||||
"create a queue for you.", _name);
|
||||
"create a queue for you.", self.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _queue;
|
||||
return _methodQueue;
|
||||
}
|
||||
|
||||
- (void)dispatchBlock:(dispatch_block_t)block
|
||||
- (void)invalidate
|
||||
{
|
||||
[self dispatchBlock:block dispatchGroup:NULL];
|
||||
}
|
||||
|
||||
- (void)dispatchBlock:(dispatch_block_t)block
|
||||
dispatchGroup:(dispatch_group_t)group
|
||||
{
|
||||
if (self.queue == RCTJSThread) {
|
||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
|
||||
} else if (self.queue) {
|
||||
if (group != NULL) {
|
||||
dispatch_group_async(group, self.queue, block);
|
||||
} else {
|
||||
dispatch_async(self.queue, block);
|
||||
}
|
||||
}
|
||||
_methodQueue = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface RCTModuleMap : NSDictionary
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)modulesByName NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTModuleMap.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
@implementation RCTModuleMap
|
||||
{
|
||||
NSDictionary *_modulesByName;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:aDecoder)
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithObjects:(const id [])objects
|
||||
forKeys:(const id<NSCopying> [])keys
|
||||
count:(NSUInteger)cnt)
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)modulesByName
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_modulesByName = [modulesByName copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)count
|
||||
{
|
||||
return _modulesByName.count;
|
||||
}
|
||||
|
||||
//declared in RCTBridge.m
|
||||
extern BOOL RCTBridgeModuleClassIsRegistered(Class cls);
|
||||
|
||||
- (id)objectForKey:(NSString *)moduleName
|
||||
{
|
||||
id<RCTBridgeModule> module = _modulesByName[moduleName];
|
||||
if (RCT_DEBUG) {
|
||||
if (module) {
|
||||
Class moduleClass = [module class];
|
||||
if (!RCTBridgeModuleClassIsRegistered(moduleClass)) {
|
||||
RCTLogError(@"Class %@ was not exported. Did you forget to use "
|
||||
"RCT_EXPORT_MODULE()?", moduleClass);
|
||||
}
|
||||
} else {
|
||||
Class moduleClass = NSClassFromString(moduleName);
|
||||
module = _modulesByName[moduleName];
|
||||
if (module) {
|
||||
RCTLogError(@"bridge.modules[name] expects a module name, not a class "
|
||||
"name. Did you mean to pass '%@' instead?",
|
||||
RCTBridgeModuleNameForClass(moduleClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
- (NSEnumerator *)keyEnumerator
|
||||
{
|
||||
return [_modulesByName keyEnumerator];
|
||||
}
|
||||
|
||||
- (NSArray<id<RCTBridgeModule>> *)allValues
|
||||
{
|
||||
// don't perform validation in this case because we only want to error when
|
||||
// an invalid module is specifically requested
|
||||
return _modulesByName.allValues;
|
||||
}
|
||||
|
||||
@end
|
|
@ -79,15 +79,14 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(sendTimespans)
|
||||
name:RCTContentDidAppearNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
_bridge = bridge;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(sendTimespans)
|
||||
name:RCTContentDidAppearNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
|
|
@ -27,6 +27,10 @@ RCT_EXTERN id RCTJSONClean(id object);
|
|||
// Get MD5 hash of a string
|
||||
RCT_EXTERN NSString *RCTMD5Hash(NSString *string);
|
||||
|
||||
// Execute the specified block on the main thread. Unlike dispatch_sync/async
|
||||
// this will not context-switch if we're already running on the main thread.
|
||||
RCT_EXTERN void RCTExecuteOnMainThread(dispatch_block_t block, BOOL sync);
|
||||
|
||||
// Get screen metrics in a thread-safe way
|
||||
RCT_EXTERN CGFloat RCTScreenScale(void);
|
||||
RCT_EXTERN CGSize RCTScreenSize(void);
|
||||
|
|
|
@ -183,18 +183,29 @@ NSString *RCTMD5Hash(NSString *string)
|
|||
];
|
||||
}
|
||||
|
||||
void RCTExecuteOnMainThread(dispatch_block_t block, BOOL sync)
|
||||
{
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else if (sync) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
block();
|
||||
});
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
block();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat RCTScreenScale()
|
||||
{
|
||||
static CGFloat scale;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
if (![NSThread isMainThread]) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
scale = [UIScreen mainScreen].scale;
|
||||
});
|
||||
} else {
|
||||
RCTExecuteOnMainThread(^{
|
||||
scale = [UIScreen mainScreen].scale;
|
||||
}
|
||||
}, YES);
|
||||
});
|
||||
|
||||
return scale;
|
||||
|
@ -205,13 +216,9 @@ CGSize RCTScreenSize()
|
|||
static CGSize size;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
if (![NSThread isMainThread]) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
size = [UIScreen mainScreen].bounds.size;
|
||||
});
|
||||
} else {
|
||||
RCTExecuteOnMainThread(^{
|
||||
size = [UIScreen mainScreen].bounds.size;
|
||||
}
|
||||
}, YES);
|
||||
});
|
||||
|
||||
return size;
|
||||
|
|
|
@ -59,6 +59,8 @@ RCT_EXPORT_MODULE()
|
|||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
// TODO: can this be moved out of the startup path?
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(didReceiveNewContentSizeCategory:)
|
||||
name:UIContentSizeCategoryDidChangeNotification
|
||||
|
@ -176,7 +178,7 @@ RCT_EXPORT_METHOD(getCurrentVoiceOverState:(RCTResponseSenderBlock)callback
|
|||
|
||||
- (RCTAccessibilityManager *)accessibilityManager
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTAccessibilityManager class])];
|
||||
return [self moduleForClass:[RCTAccessibilityManager class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -28,17 +28,6 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_alerts = [NSMutableArray new];
|
||||
_alertControllers = [NSMutableArray new];
|
||||
_alertCallbacks = [NSMutableArray new];
|
||||
_alertButtonKeys = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return dispatch_get_main_queue();
|
||||
|
@ -118,6 +107,11 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
|
|||
index ++;
|
||||
}
|
||||
|
||||
if (!_alerts) {
|
||||
_alerts = [NSMutableArray new];
|
||||
_alertCallbacks = [NSMutableArray new];
|
||||
_alertButtonKeys = [NSMutableArray new];
|
||||
}
|
||||
[_alerts addObject:alertView];
|
||||
[_alertCallbacks addObject:callback ?: ^(__unused id unused) {}];
|
||||
[_alertButtonKeys addObject:buttonKeys];
|
||||
|
@ -175,6 +169,11 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
|
|||
}]];
|
||||
}
|
||||
|
||||
if (!_alertControllers) {
|
||||
_alertControllers = [NSMutableArray new];
|
||||
}
|
||||
[_alertControllers addObject:alertController];
|
||||
|
||||
[presentingController presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,27 +44,26 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
|
||||
_lastKnownState = RCTCurrentAppBackgroundState();
|
||||
|
||||
for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
|
||||
UIApplicationDidEnterBackgroundNotification,
|
||||
UIApplicationDidFinishLaunchingNotification]) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleAppStateDidChange)
|
||||
name:name
|
||||
object:nil];
|
||||
}
|
||||
// Is this thread-safe?
|
||||
_lastKnownState = RCTCurrentAppBackgroundState();
|
||||
|
||||
for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
|
||||
UIApplicationDidEnterBackgroundNotification,
|
||||
UIApplicationDidFinishLaunchingNotification]) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleMemoryWarning)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
selector:@selector(handleAppStateDidChange)
|
||||
name:name
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleMemoryWarning)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)handleMemoryWarning
|
||||
|
|
|
@ -34,23 +34,6 @@ RCT_EXPORT_MODULE()
|
|||
isEnabled = enabled;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(hide)
|
||||
name:RCTJavaScriptDidLoadNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(hide)
|
||||
name:RCTJavaScriptDidFailToLoadNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
@ -59,6 +42,16 @@ RCT_EXPORT_MODULE()
|
|||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(hide)
|
||||
name:RCTJavaScriptDidLoadNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(hide)
|
||||
name:RCTJavaScriptDidFailToLoadNotification
|
||||
object:nil];
|
||||
[self showWithURL:bridge.bundleURL];
|
||||
}
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
// Check if live reloading is available
|
||||
_liveReloadURL = nil;
|
||||
RCTSourceCode *sourceCodeModule = _bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
|
||||
RCTSourceCode *sourceCodeModule = [_bridge moduleForClass:[RCTSourceCode class]];
|
||||
if (!sourceCodeModule.scriptURL) {
|
||||
if (!sourceCodeModule) {
|
||||
RCTLogWarn(@"RCTSourceCode module not found");
|
||||
|
@ -614,7 +614,7 @@ RCT_EXPORT_METHOD(reload)
|
|||
- (RCTDevMenu *)devMenu
|
||||
{
|
||||
#if RCT_DEV
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTDevMenu class])];
|
||||
return [self moduleForClass:[RCTDevMenu class]];
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
@interface RCTExceptionsManager : NSObject <RCTBridgeModule>
|
||||
|
||||
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate;
|
||||
|
||||
@property (nonatomic, assign) NSUInteger maxReloadAttempts;
|
||||
|
||||
|
|
|
@ -27,18 +27,12 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
if ((self = [self init])) {
|
||||
_delegate = delegate;
|
||||
_maxReloadAttempts = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithDelegate:nil];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
|
||||
stack:(NSDictionaryArray *)stack
|
||||
exceptionId:(nonnull NSNumber *)exceptionId)
|
||||
|
|
|
@ -107,8 +107,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
{
|
||||
if ((self.hidden && shouldShow) || (!self.hidden && [_lastErrorMessage isEqualToString:message])) {
|
||||
_lastStackTrace = stack;
|
||||
// message is displayed using UILabel, which is unable to render text of unlimited length, so we truncate it
|
||||
_lastErrorMessage = [message substringToIndex:MIN(10000, message.length)];
|
||||
// message is displayed using UILabel, which is unable to render text of
|
||||
// unlimited length, so we truncate it
|
||||
_lastErrorMessage = [message substringToIndex:MIN((NSUInteger)10000, message.length)];
|
||||
|
||||
[_stackTraceTableView reloadData];
|
||||
|
||||
|
@ -326,7 +327,7 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (RCTRedBox *)redBox
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTRedBox class])];
|
||||
return [self moduleForClass:[RCTRedBox class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -46,14 +46,13 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (instancetype)init
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:self selector:@selector(applicationDidChangeStatusBarFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
|
||||
[nc addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
_bridge = bridge;
|
||||
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:self selector:@selector(applicationDidChangeStatusBarFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
|
||||
[nc addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
|
|
@ -179,14 +179,6 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
|
|||
|
||||
@end
|
||||
|
||||
@interface RCTUIManager ()
|
||||
|
||||
// NOTE: these are properties so that they can be accessed by unit tests
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, RCTShadowView *> *shadowViewRegistry; // RCT thread only
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIView *> *viewRegistry; // Main thread only
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUIManager
|
||||
{
|
||||
dispatch_queue_t _shadowQueue;
|
||||
|
@ -199,6 +191,9 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
|
|||
RCTLayoutAnimation *_nextLayoutAnimation; // RCT thread only
|
||||
RCTLayoutAnimation *_layoutAnimation; // Main thread only
|
||||
|
||||
NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
|
||||
NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry; // Main thread only
|
||||
|
||||
// Keyed by viewName
|
||||
NSDictionary *_componentDataByName;
|
||||
|
||||
|
@ -214,31 +209,6 @@ RCT_EXPORT_MODULE()
|
|||
*/
|
||||
extern NSString *RCTBridgeModuleNameForClass(Class cls);
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
const char *queueName = "com.facebook.React.ShadowQueue";
|
||||
|
||||
if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
|
||||
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
|
||||
_shadowQueue = dispatch_queue_create(queueName, attr);
|
||||
} else {
|
||||
_shadowQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_set_target_queue(_shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
}
|
||||
|
||||
_shadowViewRegistry = [NSMutableDictionary new];
|
||||
_viewRegistry = [NSMutableDictionary new];
|
||||
|
||||
// Internal resources
|
||||
_pendingUIBlocks = [NSMutableArray new];
|
||||
_rootViewTags = [NSMutableSet new];
|
||||
|
||||
_bridgeTransactionListeners = [NSMutableSet new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveNewContentSizeMultiplier
|
||||
{
|
||||
__weak RCTUIManager *weakSelf = self;
|
||||
|
@ -276,18 +246,45 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
|
|||
});
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
|
||||
{
|
||||
// NOTE: this method only exists so that it can be accessed by unit tests
|
||||
if (!_shadowViewRegistry) {
|
||||
_shadowViewRegistry = [NSMutableDictionary new];
|
||||
}
|
||||
return _shadowViewRegistry;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry
|
||||
{
|
||||
// NOTE: this method only exists so that it can be accessed by unit tests
|
||||
if (!_viewRegistry) {
|
||||
_viewRegistry = [NSMutableDictionary new];
|
||||
}
|
||||
return _viewRegistry;
|
||||
}
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
RCTAssert(_bridge == nil, @"Should not re-use same UIIManager instance");
|
||||
|
||||
_bridge = bridge;
|
||||
|
||||
_shadowViewRegistry = [NSMutableDictionary new];
|
||||
_viewRegistry = [NSMutableDictionary new];
|
||||
|
||||
// Internal resources
|
||||
_pendingUIBlocks = [NSMutableArray new];
|
||||
_rootViewTags = [NSMutableSet new];
|
||||
|
||||
_bridgeTransactionListeners = [NSMutableSet new];
|
||||
|
||||
// Get view managers from bridge
|
||||
NSMutableDictionary *componentDataByName = [NSMutableDictionary new];
|
||||
for (RCTViewManager *manager in _bridge.modules.allValues) {
|
||||
if ([manager isKindOfClass:[RCTViewManager class]]) {
|
||||
RCTComponentData *componentData = [[RCTComponentData alloc] initWithManager:manager];
|
||||
for (Class moduleClass in _bridge.moduleClasses) {
|
||||
if ([moduleClass isSubclassOfClass:[RCTViewManager class]]) {
|
||||
RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass
|
||||
bridge:_bridge];
|
||||
componentDataByName[componentData.name] = componentData;
|
||||
}
|
||||
}
|
||||
|
@ -302,6 +299,17 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
|
|||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
if (!_shadowQueue) {
|
||||
const char *queueName = "com.facebook.React.ShadowQueue";
|
||||
|
||||
if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
|
||||
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
|
||||
_shadowQueue = dispatch_queue_create(queueName, attr);
|
||||
} else {
|
||||
_shadowQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_set_target_queue(_shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
}
|
||||
}
|
||||
return _shadowQueue;
|
||||
}
|
||||
|
||||
|
@ -1126,12 +1134,11 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
|||
[_componentDataByName enumerateKeysAndObjectsUsingBlock:
|
||||
^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) {
|
||||
|
||||
RCTViewManager *manager = componentData.manager;
|
||||
NSMutableDictionary<NSString *, id> *constantsNamespace =
|
||||
[NSMutableDictionary dictionaryWithDictionary:allJSConstants[name]];
|
||||
|
||||
// Add manager class
|
||||
constantsNamespace[@"Manager"] = RCTBridgeModuleNameForClass([manager class]);
|
||||
constantsNamespace[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass);
|
||||
|
||||
// Add native props
|
||||
NSDictionary<NSString *, id> *viewConfig = [componentData viewConfig];
|
||||
|
@ -1216,7 +1223,7 @@ static UIView *_jsResponder;
|
|||
|
||||
- (RCTUIManager *)uiManager
|
||||
{
|
||||
return self.modules[RCTBridgeModuleNameForClass([RCTUIManager class])];
|
||||
return [self moduleForClass:[RCTUIManager class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -30,6 +30,13 @@ NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
|
|||
|
||||
#if RCT_DEV
|
||||
|
||||
@interface RCTBridge ()
|
||||
|
||||
- (void)dispatchBlock:(dispatch_block_t)block
|
||||
queue:(dispatch_queue_t)queue;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Constants
|
||||
|
||||
NSString const *RCTProfileTraceEvents = @"traceEvents";
|
||||
|
@ -211,7 +218,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
|
|||
RCTProfileHookedModules = YES;
|
||||
|
||||
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
|
||||
[moduleData dispatchBlock:^{
|
||||
[bridge dispatchBlock:^{
|
||||
Class moduleClass = moduleData.moduleClass;
|
||||
Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
|
||||
|
||||
|
@ -242,7 +249,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
|
|||
|
||||
objc_registerClassPair(proxyClass);
|
||||
object_setClass(moduleData.instance, proxyClass);
|
||||
}];
|
||||
} queue:moduleData.methodQueue];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; };
|
||||
137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; };
|
||||
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; };
|
||||
1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 1385D0331B665AAE000A309B /* RCTModuleMap.m */; };
|
||||
13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; };
|
||||
13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; };
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
|
||||
|
@ -48,6 +47,7 @@
|
|||
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
|
||||
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
|
||||
13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+React.m */; };
|
||||
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
|
||||
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 13F17A841B8493E5007D4C75 /* RCTRedBox.m */; };
|
||||
14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */; };
|
||||
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
|
||||
|
@ -57,7 +57,6 @@
|
|||
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
|
||||
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; };
|
||||
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; };
|
||||
14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
|
||||
14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
|
||||
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
|
||||
14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
|
||||
|
@ -134,8 +133,6 @@
|
|||
137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItemManager.m; sourceTree = "<group>"; };
|
||||
137327E51AA5CF210034F82E /* RCTTabBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarManager.h; sourceTree = "<group>"; };
|
||||
137327E61AA5CF210034F82E /* RCTTabBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarManager.m; sourceTree = "<group>"; };
|
||||
1385D0331B665AAE000A309B /* RCTModuleMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMap.m; sourceTree = "<group>"; };
|
||||
1385D0351B6661DB000A309B /* RCTModuleMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModuleMap.h; sourceTree = "<group>"; };
|
||||
13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevLoadingView.h; sourceTree = "<group>"; };
|
||||
13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevLoadingView.m; sourceTree = "<group>"; };
|
||||
13A0C2871B74F71200B29F6F /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevMenu.h; sourceTree = "<group>"; };
|
||||
|
@ -432,7 +429,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
14BF71811C04795500C97D0C /* RCTMacros.h */,
|
||||
14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */,
|
||||
14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */,
|
||||
14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */,
|
||||
14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */,
|
||||
|
@ -440,6 +436,7 @@
|
|||
1450FF811BCFF28A00208362 /* RCTProfile.m */,
|
||||
1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */,
|
||||
1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */,
|
||||
14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */,
|
||||
1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */,
|
||||
);
|
||||
path = Profiler;
|
||||
|
@ -506,8 +503,6 @@
|
|||
83CBBA4E1A601E3B00E9B192 /* RCTLog.m */,
|
||||
14C2CA721B3AC64300E6CBB2 /* RCTModuleData.h */,
|
||||
14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */,
|
||||
1385D0351B6661DB000A309B /* RCTModuleMap.h */,
|
||||
1385D0331B665AAE000A309B /* RCTModuleMap.m */,
|
||||
14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */,
|
||||
14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */,
|
||||
142014181B32094000CC17BA /* RCTPerformanceLogger.h */,
|
||||
|
@ -643,6 +638,7 @@
|
|||
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */,
|
||||
14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */,
|
||||
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */,
|
||||
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
|
||||
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
|
||||
14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
|
||||
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
|
||||
|
@ -683,8 +679,6 @@
|
|||
83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
|
||||
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
|
||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||
14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */,
|
||||
1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */,
|
||||
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
|
||||
83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,
|
||||
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
|
||||
|
|
|
@ -12,16 +12,19 @@
|
|||
#import "RCTComponent.h"
|
||||
#import "RCTDefines.h"
|
||||
|
||||
@class RCTBridge;
|
||||
@class RCTShadowView;
|
||||
@class RCTViewManager;
|
||||
@class UIView;
|
||||
|
||||
@interface RCTComponentData : NSObject
|
||||
|
||||
@property (nonatomic, readonly) Class managerClass;
|
||||
@property (nonatomic, copy, readonly) NSString *name;
|
||||
@property (nonatomic, strong, readonly) RCTViewManager *manager;
|
||||
|
||||
- (instancetype)initWithManager:(RCTViewManager *)manager NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithManagerClass:(Class)managerClass
|
||||
bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props;
|
||||
- (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag;
|
||||
|
|
|
@ -44,16 +44,21 @@ typedef void (^RCTPropBlock)(id<RCTComponent> view, id json);
|
|||
RCTShadowView *_defaultShadowView;
|
||||
NSMutableDictionary<NSString *, RCTPropBlock> *_viewPropBlocks;
|
||||
NSMutableDictionary<NSString *, RCTPropBlock> *_shadowPropBlocks;
|
||||
RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
- (instancetype)initWithManager:(RCTViewManager *)manager
|
||||
@synthesize manager = _manager;
|
||||
|
||||
- (instancetype)initWithManagerClass:(Class)managerClass
|
||||
bridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_manager = manager;
|
||||
_bridge = bridge;
|
||||
_managerClass = managerClass;
|
||||
_viewPropBlocks = [NSMutableDictionary new];
|
||||
_shadowPropBlocks = [NSMutableDictionary new];
|
||||
|
||||
_name = RCTBridgeModuleNameForClass([manager class]);
|
||||
_name = RCTBridgeModuleNameForClass(_managerClass);
|
||||
RCTAssert(_name.length, @"Invalid moduleName '%@'", _name);
|
||||
if ([_name hasSuffix:@"Manager"]) {
|
||||
_name = [_name substringToIndex:_name.length - @"Manager".length];
|
||||
|
@ -62,13 +67,21 @@ typedef void (^RCTPropBlock)(id<RCTComponent> view, id json);
|
|||
return self;
|
||||
}
|
||||
|
||||
- (RCTViewManager *)manager
|
||||
{
|
||||
if (!_manager) {
|
||||
_manager = [_bridge moduleForClass:_managerClass];
|
||||
}
|
||||
return _manager;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props
|
||||
{
|
||||
RCTAssertMainThread();
|
||||
|
||||
UIView *view = (UIView *)(props ? [_manager viewWithProps:props] : [_manager view]);
|
||||
UIView *view = (UIView *)(props ? [self.manager viewWithProps:props] : [_manager view]);
|
||||
view.reactTag = tag;
|
||||
view.multipleTouchEnabled = YES;
|
||||
view.userInteractionEnabled = YES; // required for touch handling
|
||||
|
@ -78,7 +91,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
- (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag
|
||||
{
|
||||
RCTShadowView *shadowView = [_manager shadowView];
|
||||
RCTShadowView *shadowView = [self.manager shadowView];
|
||||
shadowView.reactTag = tag;
|
||||
shadowView.viewName = _name;
|
||||
return shadowView;
|
||||
|
@ -310,15 +323,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
- (NSDictionary<NSString *, id> *)viewConfig
|
||||
{
|
||||
Class managerClass = [_manager class];
|
||||
|
||||
NSMutableArray<NSString *> *directEvents = [NSMutableArray new];
|
||||
if (RCTClassOverridesInstanceMethod(managerClass, @selector(customDirectEventTypes))) {
|
||||
NSArray<NSString *> *events = [_manager customDirectEventTypes];
|
||||
if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customDirectEventTypes))) {
|
||||
NSArray<NSString *> *events = [self.manager customDirectEventTypes];
|
||||
if (RCT_DEBUG) {
|
||||
RCTAssert(!events || [events isKindOfClass:[NSArray class]],
|
||||
@"customDirectEventTypes must return an array, but %@ returned %@",
|
||||
managerClass, [events class]);
|
||||
_managerClass, [events class]);
|
||||
}
|
||||
for (NSString *event in events) {
|
||||
[directEvents addObject:RCTNormalizeInputEventName(event)];
|
||||
|
@ -326,12 +337,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
}
|
||||
|
||||
NSMutableArray<NSString *> *bubblingEvents = [NSMutableArray new];
|
||||
if (RCTClassOverridesInstanceMethod(managerClass, @selector(customBubblingEventTypes))) {
|
||||
NSArray<NSString *> *events = [_manager customBubblingEventTypes];
|
||||
if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customBubblingEventTypes))) {
|
||||
NSArray<NSString *> *events = [self.manager customBubblingEventTypes];
|
||||
if (RCT_DEBUG) {
|
||||
RCTAssert(!events || [events isKindOfClass:[NSArray class]],
|
||||
@"customBubblingEventTypes must return an array, but %@ returned %@",
|
||||
managerClass, [events class]);
|
||||
_managerClass, [events class]);
|
||||
}
|
||||
for (NSString *event in events) {
|
||||
[bubblingEvents addObject:RCTNormalizeInputEventName(event)];
|
||||
|
@ -340,7 +351,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
unsigned int count = 0;
|
||||
NSMutableDictionary *propTypes = [NSMutableDictionary new];
|
||||
Method *methods = class_copyMethodList(object_getClass(managerClass), &count);
|
||||
Method *methods = class_copyMethodList(object_getClass(_managerClass), &count);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
Method method = methods[i];
|
||||
SEL selector = method_getName(method);
|
||||
|
@ -349,7 +360,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
NSRange nameRange = [methodName rangeOfString:@"_"];
|
||||
if (nameRange.length) {
|
||||
NSString *name = [methodName substringFromIndex:nameRange.location + 1];
|
||||
NSString *type = ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(managerClass, selector)[0];
|
||||
NSString *type = ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(_managerClass, selector)[0];
|
||||
if (RCT_DEBUG && propTypes[name] && ![propTypes[name] isEqualToString:type]) {
|
||||
RCTLogError(@"Property '%@' of component '%@' redefined from '%@' "
|
||||
"to '%@'", name, _name, propTypes[name], type);
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
#import "RCTModalHostViewController.h"
|
||||
|
||||
@implementation RCTModalHostViewController {
|
||||
@implementation RCTModalHostViewController
|
||||
{
|
||||
CGRect _lastViewFrame;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,18 +20,12 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_hostViews = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
UIView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge];
|
||||
if (_hostViews) {
|
||||
_hostViews = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
[_hostViews addObject:view];
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
|
|||
* allowing the manager (or the views that it manages) to manipulate the view
|
||||
* hierarchy and send events back to the JS context.
|
||||
*/
|
||||
@property (nonatomic, weak) RCTBridge *bridge;
|
||||
@property (nonatomic, weak, readonly) RCTBridge *bridge;
|
||||
|
||||
/**
|
||||
* This method instantiates a native view to be managed by the module. Override
|
||||
|
|
|
@ -95,11 +95,6 @@ RCT_EXPORT_MODULE()
|
|||
return @[];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)constantsToExport
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(__unused RCTShadowView *)shadowView
|
||||
{
|
||||
return nil;
|
||||
|
|
Loading…
Reference in New Issue