From a87ba4ab4c79c393cd06f97954bc1ad6b6e360db Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Fri, 18 Sep 2015 15:01:21 -0700 Subject: [PATCH] Prepare the bridge for C++ Reviewed By: @nicklockwood Differential Revision: D2432291 --- React/Base/RCTBatchedBridge.m | 15 +++++++-------- React/Base/RCTBridgeMethod.h | 29 +++++++++++++++++++++++++++++ React/Base/RCTBridgeModule.h | 18 ++++++++++++------ React/Base/RCTModuleData.m | 9 +++++++-- React/Base/RCTModuleMethod.h | 10 +++------- React/Base/RCTModuleMethod.m | 16 ++++++++++++++++ 6 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 React/Base/RCTBridgeMethod.h diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 8f5de7330..de4936002 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -18,7 +18,7 @@ #import "RCTLog.h" #import "RCTModuleData.h" #import "RCTModuleMap.h" -#import "RCTModuleMethod.h" +#import "RCTBridgeMethod.h" #import "RCTPerformanceLogger.h" #import "RCTPerfStats.h" #import "RCTProfile.h" @@ -767,7 +767,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR return NO; } - RCTModuleMethod *method = moduleData.methods[methodID]; + id method = moduleData.methods[methodID]; if (RCT_DEBUG && !method) { RCTLogError(@"Unknown methodID: %zd for module: %zd (%@)", methodID, moduleID, moduleData.name); return NO; @@ -783,12 +783,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR } } - RCTProfileEndEvent(0, @"objc_call", @{ - @"module": NSStringFromClass(method.moduleClass), - @"method": method.JSMethodName, - @"selector": NSStringFromSelector(method.selector), - @"args": RCTJSONStringify(RCTNullIfNil(params), NULL), - }); + NSMutableDictionary *args = [method.profileArgs mutableCopy]; + [args setValue:method.JSMethodName forKey:@"method"]; + [args setValue:RCTJSONStringify(RCTNullIfNil(params), NULL) forKey:@"args"]; + + RCTProfileEndEvent(0, @"objc_call", args); return YES; } diff --git a/React/Base/RCTBridgeMethod.h b/React/Base/RCTBridgeMethod.h new file mode 100644 index 000000000..cb322c261 --- /dev/null +++ b/React/Base/RCTBridgeMethod.h @@ -0,0 +1,29 @@ +/** + * 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 + +@class RCTBridge; + +typedef NS_ENUM(NSUInteger, RCTFunctionType) { + RCTFunctionTypeNormal, + RCTFunctionTypePromise, +}; + +@protocol RCTBridgeMethod + +@property (nonatomic, copy, readonly) NSString *JSMethodName; +@property (nonatomic, copy, readonly) NSDictionary *profileArgs; +@property (nonatomic, readonly) RCTFunctionType functionType; + +- (void)invokeWithBridge:(RCTBridge *)bridge + module:(id)module + arguments:(NSArray *)arguments; + +@end diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h index 782c5dffa..93f8f6e98 100644 --- a/React/Base/RCTBridgeModule.h +++ b/React/Base/RCTBridgeModule.h @@ -210,15 +210,21 @@ RCT_EXTERN void RCTRegisterModule(Class); \ #define RCT_EXTERN_REMAP_METHOD(js_name, method) \ + (NSArray *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \ return @[@#js_name, @#method]; \ - } \ + } + +/** + * Injects methods into JS. Entries in this array are used in addition to any + * methods defined using the macros above. This method is called only once, + * before registration. + */ +- (NSArray *)methodsToExport; /** * Injects constants into JS. These constants are made accessible via - * NativeModules.ModuleName.X. This method is called when the module is - * registered by the bridge. It is only called once for the lifetime of the - * bridge, so it is not suitable for returning dynamic values, but may be - * used for long-lived values such as session keys, that are regenerated only - * as part of a reload of the entire React application. + * NativeModules.ModuleName.X. It is only called once for the lifetime of the + * bridge, so it is not suitable for returning dynamic values, but may be used + * for long-lived values such as session keys, that are regenerated only as + * part of a reload of the entire React application. */ - (NSDictionary *)constantsToExport; diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m index dfc21ea3f..23f46cb79 100644 --- a/React/Base/RCTModuleData.m +++ b/React/Base/RCTModuleData.m @@ -49,6 +49,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init); { if (!_methods) { NSMutableArray *moduleMethods = [NSMutableArray new]; + + if ([_instance respondsToSelector:@selector(methodsToExport)]) { + [moduleMethods addObjectsFromArray:[_instance methodsToExport]]; + } + unsigned int methodCount; Method *methods = class_copyMethodList(object_getClass(_moduleClass), &methodCount); @@ -58,7 +63,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init); if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) { IMP imp = method_getImplementation(method); NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); - RCTModuleMethod *moduleMethod = + id moduleMethod = [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1] JSMethodName:entries[0] moduleClass:_moduleClass]; @@ -84,7 +89,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init); } NSMutableDictionary *methodconfig = [NSMutableDictionary new]; - [self.methods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger idx, __unused BOOL *stop) { + [self.methods enumerateObjectsUsingBlock:^(id method, NSUInteger idx, __unused BOOL *stop) { methodconfig[method.JSMethodName] = @{ @"methodID": @(idx), @"type": method.functionType == RCTFunctionTypePromise ? @"remoteAsync" : @"remote", diff --git a/React/Base/RCTModuleMethod.h b/React/Base/RCTModuleMethod.h index 5768ac4bc..ff5c1cda6 100644 --- a/React/Base/RCTModuleMethod.h +++ b/React/Base/RCTModuleMethod.h @@ -9,12 +9,9 @@ #import -@class RCTBridge; +#import "RCTBridgeMethod.h" -typedef NS_ENUM(NSUInteger, RCTFunctionType) { - RCTFunctionTypeNormal, - RCTFunctionTypePromise, -}; +@class RCTBridge; typedef NS_ENUM(NSUInteger, RCTNullability) { RCTNullabilityUnspecified, @@ -30,9 +27,8 @@ typedef NS_ENUM(NSUInteger, RCTNullability) { @end -@interface RCTModuleMethod : NSObject +@interface RCTModuleMethod : NSObject -@property (nonatomic, copy, readonly) NSString *JSMethodName; @property (nonatomic, readonly) Class moduleClass; @property (nonatomic, readonly) SEL selector; @property (nonatomic, readonly) RCTFunctionType functionType; diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m index 2cb0ce476..f01e60cfd 100644 --- a/React/Base/RCTModuleMethod.m +++ b/React/Base/RCTModuleMethod.m @@ -50,8 +50,11 @@ typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id); NSArray *_argumentBlocks; NSString *_objCMethodName; SEL _selector; + NSDictionary *_profileArgs; } +@synthesize JSMethodName = _JSMethodName; + static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index, id valueOrType, const char *issue) { @@ -370,6 +373,19 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments) return _selector; } +- (NSDictionary *)profileArgs +{ + if (_profileArgs) { + // This sets _selector + [self processMethodSignature]; + _profileArgs = @{ + @"module": NSStringFromClass(_moduleClass), + @"selector": NSStringFromSelector(_selector), + }; + } + return _profileArgs; +} + - (void)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments