Replace exported method registration with statically allocated struct

Reviewed By: fromcelticpark

Differential Revision: D5389383

fbshipit-source-id: 9eb29b254b616574966b43ad24aa880d44589652
This commit is contained in:
Pieter De Baets 2017-07-24 06:46:01 -07:00 committed by Facebook Github Bot
parent d94f3e4b98
commit cb12080179
15 changed files with 161 additions and 143 deletions

View File

@ -15,16 +15,17 @@
#define FB_REFERENCE_IMAGE_DIR ""
#endif
#define RCT_RUN_RUNLOOP_WHILE(CONDITION) \
{ \
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
while ((CONDITION)) { \
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
if ([timeout timeIntervalSinceNow] <= 0) { \
XCTFail(@"Runloop timed out before condition was met"); \
break; \
} \
} \
#define RCT_RUN_RUNLOOP_WHILE(CONDITION) \
{ \
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
NSRunLoop *runloop = [NSRunLoop mainRunLoop]; \
while ((CONDITION)) { \
[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; \
if ([timeout timeIntervalSinceNow] <= 0) { \
XCTFail(@"Runloop timed out before condition was met"); \
break; \
} \
} \
}
/**

View File

@ -112,9 +112,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
AllocationTestModule *module = [AllocationTestModule new];
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:^{
return @[module];
}
moduleProvider:^{ return @[module]; }
launchOptions:nil];
XCTAssertTrue(module.isValid, @"AllocationTestModule should be valid");
(void)bridge;
@ -130,12 +128,10 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
@autoreleasepool {
AllocationTestModule *module = [AllocationTestModule new];
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:^{
return @[module];
}
moduleProvider:^{ return @[module]; }
launchOptions:nil];
XCTAssertNotNil(module, @"AllocationTestModule should have been created");
weakModule = module;
XCTAssertNotNil(weakModule, @"AllocationTestModule should have been created");
(void)bridge;
}
@ -145,11 +141,18 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
- (void)testModuleMethodsAreDeallocated
{
static RCTMethodInfo methodInfo = {
.objcName = "test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d",
.jsName = "",
.isSync = false
};
__weak RCTModuleMethod *weakMethod;
@autoreleasepool {
__autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:@"test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d" JSMethodName:@"" isSync:NO moduleClass:[AllocationTestModule class]];
weakMethod = method;
__autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithExportedMethod:&methodInfo
moduleClass:[AllocationTestModule class]];
XCTAssertNotNil(method, @"RCTModuleMethod should have been created");
weakMethod = method;
}
RCT_RUN_RUNLOOP_WHILE(weakMethod)
@ -172,7 +175,6 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
#if !TARGET_OS_TV // userInteractionEnabled is true for Apple TV views
XCTAssertFalse(rootContentView.userInteractionEnabled, @"RCTContentView should have been invalidated");
#endif
}
- (void)testUnderlyingBridgeIsDeallocated

View File

@ -19,12 +19,12 @@
@implementation RCTMethodArgumentTests
extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes);
extern SEL RCTParseMethodSignature(const char *methodSignature, NSArray **argTypes);
- (void)testOneArgument
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSInteger)foo";
const char *methodSignature = "foo:(NSInteger)foo";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
@ -34,7 +34,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testTwoArguments
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSInteger)foo bar:(BOOL)bar";
const char *methodSignature = "foo:(NSInteger)foo bar:(BOOL)bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -45,7 +45,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testSpaces
{
NSArray *arguments;
NSString *methodSignature = @"foo : (NSInteger)foo bar : (BOOL) bar";
const char *methodSignature = "foo : (NSInteger)foo bar : (BOOL) bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -56,7 +56,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testNewlines
{
NSArray *arguments;
NSString *methodSignature = @"foo : (NSInteger)foo\nbar : (BOOL) bar";
const char *methodSignature = "foo : (NSInteger)foo\nbar : (BOOL) bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -67,7 +67,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testUnnamedArgs
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSInteger)foo:(BOOL)bar";
const char *methodSignature = "foo:(NSInteger)foo:(BOOL)bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo::");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -78,7 +78,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testUntypedUnnamedArgs
{
NSArray *arguments;
NSString *methodSignature = @"foo:foo:bar:bar";
const char *methodSignature = "foo:foo:bar:bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:::");
XCTAssertEqual(arguments.count, (NSUInteger)3);
@ -90,7 +90,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testAttributes
{
NSArray *arguments;
NSString *methodSignature = @"foo:(__attribute__((unused)) NSString *)foo bar:(__unused BOOL)bar";
const char *methodSignature = "foo:(__attribute__((unused)) NSString *)foo bar:(__unused BOOL)bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -101,7 +101,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testNullability
{
NSArray *arguments;
NSString *methodSignature = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz";
const char *methodSignature = "foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:baz:");
XCTAssertEqual(arguments.count, (NSUInteger)3);
@ -116,7 +116,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testSemicolonStripping
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSString *)foo bar:(BOOL)bar;";
const char *methodSignature = "foo:(NSString *)foo bar:(BOOL)bar;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -127,7 +127,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testUnused
{
NSArray *arguments;
NSString *methodSignature = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar";
const char *methodSignature = "foo:(__unused NSString *)foo bar:(NSNumber *)bar";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2);
@ -140,7 +140,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testGenericArray
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSArray<NSString *> *)foo;";
const char *methodSignature = "foo:(NSArray<NSString *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
@ -150,7 +150,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testNestedGenericArray
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSArray<NSArray<NSString *> *> *)foo;";
const char *methodSignature = "foo:(NSArray<NSArray<NSString *> *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
@ -160,7 +160,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testGenericSet
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSSet<NSNumber *> *)foo;";
const char *methodSignature = "foo:(NSSet<NSNumber *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
@ -170,7 +170,7 @@ extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes
- (void)testGenericDictionary
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSDictionary<NSString *, NSNumber *> *)foo;";
const char *methodSignature = "foo:(NSDictionary<NSString *, NSNumber *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);

View File

@ -37,18 +37,18 @@ static BOOL RCTLogsError(void (^block)(void))
CGRect _s;
}
static RCTModuleMethod *buildDefaultMethodWithMethodSignature(NSString *methodSignature) {
return [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil
isSync:NO
moduleClass:[RCTModuleMethodTests class]];
static RCTModuleMethod *buildDefaultMethodWithMethodSignature(const char *methodSignature)
{
// This leaks a RCTMethodInfo, but it's a test, so...
RCTMethodInfo *methodInfo = new RCTMethodInfo {.objcName = methodSignature, .isSync = NO};
return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]];
}
static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSignature) {
return [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil
isSync:YES
moduleClass:[RCTModuleMethodTests class]];
static RCTModuleMethod *buildSyncMethodWithMethodSignature(const char *methodSignature)
{
// This leaks a RCTMethodInfo, but it's a test, so...
RCTMethodInfo *methodInfo = new RCTMethodInfo {.objcName = methodSignature, .isSync = YES};
return [[RCTModuleMethod alloc] initWithExportedMethod:methodInfo moduleClass:[RCTModuleMethodTests class]];
}
+ (NSString *)moduleName { return nil; }
@ -62,7 +62,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testNonnull
{
NSString *methodSignature = @"doFooWithBar:(nonnull NSString *)bar";
const char *methodSignature = "doFooWithBar:(nonnull NSString *)bar";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertFalse(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[@"Hello World"]];
@ -85,7 +85,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
{
// Specifying an NSNumber param without nonnull isn't allowed
XCTAssertTrue(RCTLogsError(^{
NSString *methodSignature = @"doFooWithNumber:(NSNumber *)n";
const char *methodSignature = "doFooWithNumber:(NSNumber *)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
// Invoke method to trigger parsing
[method invokeWithBridge:nil module:self arguments:@[@1]];
@ -93,7 +93,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
}
{
NSString *methodSignature = @"doFooWithNumber:(nonnull NSNumber *)n";
const char *methodSignature = "doFooWithNumber:(nonnull NSNumber *)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
@ -101,7 +101,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
}
{
NSString *methodSignature = @"doFooWithDouble:(double)n";
const char *methodSignature = "doFooWithDouble:(double)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
@ -109,7 +109,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
}
{
NSString *methodSignature = @"doFooWithInteger:(NSInteger)n";
const char *methodSignature = "doFooWithInteger:(NSInteger)n";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
[method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
@ -119,7 +119,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testStructArgument
{
NSString *methodSignature = @"doFooWithCGRect:(CGRect)s";
const char *methodSignature = "doFooWithCGRect:(CGRect)s";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
CGRect r = CGRectMake(10, 20, 30, 40);
@ -129,7 +129,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testWhitespaceTolerance
{
NSString *methodSignature = @"doFoo : \t (NSString *)foo";
const char *methodSignature = "doFoo : \t (NSString *)foo";
__block RCTModuleMethod *method;
XCTAssertFalse(RCTLogsError(^{
@ -146,19 +146,19 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testFunctionType
{
{
NSString *methodSignature = @"doFoo";
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeNormal);
}
{
NSString *methodSignature = @"openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject";
const char *methodSignature = "openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypePromise);
}
{
NSString *methodSignature = @"echoString:(NSString *)input";
const char *methodSignature = "echoString:(NSString *)input";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertTrue(method.functionType == RCTFunctionTypeSync);
}
@ -167,14 +167,14 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testReturnsValueForSyncFunction
{
{
NSString *methodSignature = @"echoString:(NSString *)input";
const char *methodSignature = "echoString:(NSString *)input";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[@"Test String Value"]];
XCTAssertEqualObjects(result, @"Test String Value");
}
{
NSString *methodSignature = @"methodThatReturnsNil";
const char *methodSignature = "methodThatReturnsNil";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[]];
XCTAssertNil(result);
@ -183,7 +183,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testReturnsNilForDefaultFunction
{
NSString *methodSignature = @"doFoo";
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature);
id result = [method invokeWithBridge:nil module:self arguments:@[]];
XCTAssertNil(result);
@ -192,7 +192,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
- (void)testReturnTypeForSyncFunction
{
{
NSString *methodSignature = @"methodThatReturnsNil";
const char *methodSignature = "methodThatReturnsNil";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertFalse(RCTLogsError(^{
// Invoke method to trigger parsing
@ -201,7 +201,7 @@ static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSigna
}
{
NSString *methodSignature = @"doFoo";
const char *methodSignature = "doFoo";
RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature);
XCTAssertTrue(RCTLogsError(^{
// Invoke method to trigger parsing

View File

@ -1067,7 +1067,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
}
NSString *message = [NSString stringWithFormat:
@"Exception '%@' was thrown while invoking %@ on target %@ with params %@",
@"Exception '%@' was thrown while invoking %s on target %@ with params %@",
exception, method.JSMethodName, moduleData.name, params];
RCTFatal(RCTErrorWithMessage(message));
return nil;

View File

@ -30,7 +30,7 @@ static inline const char *RCTFunctionDescriptorFromType(RCTFunctionType type) {
@protocol RCTBridgeMethod <NSObject>
@property (nonatomic, copy, readonly) NSString *JSMethodName;
@property (nonatomic, readonly) const char *JSMethodName;
@property (nonatomic, readonly) RCTFunctionType functionType;
- (id)invokeWithBridge:(RCTBridge *)bridge

View File

@ -47,7 +47,17 @@ typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError
*
* NOTE: RCTJSThread is not a real libdispatch queue
*/
extern dispatch_queue_t RCTJSThread;
RCT_EXTERN dispatch_queue_t RCTJSThread;
RCT_EXTERN_C_BEGIN
typedef struct RCTMethodInfo {
const char *const jsName;
const char *const objcName;
const BOOL isSync;
} RCTMethodInfo;
RCT_EXTERN_C_END
/**
* Provides the interface needed to register a bridge module.
@ -248,9 +258,9 @@ RCT_EXTERN void RCTRegisterModule(Class); \
* and also whether this method is synchronous.
*/
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+ (NSArray *)RCT_CONCAT(__rct_export__, \
RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
return @[@#js_name, @#method, @is_blocking_synchronous_method]; \
+ (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
/**

View File

@ -16,8 +16,12 @@
*/
#if defined(__cplusplus)
#define RCT_EXTERN extern "C" __attribute__((visibility("default")))
#define RCT_EXTERN_C_BEGIN extern "C" {
#define RCT_EXTERN_C_END }
#else
#define RCT_EXTERN extern __attribute__((visibility("default")))
#define RCT_EXTERN_C_BEGIN
#define RCT_EXTERN_C_END
#endif
/**

View File

@ -270,14 +270,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
SEL selector = method_getName(method);
if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
IMP imp = method_getImplementation(method);
NSArray *entries =
((NSArray *(*)(id, SEL))imp)(_moduleClass, selector);
id<RCTBridgeMethod> moduleMethod =
[[RCTModuleMethod alloc] initWithMethodSignature:entries[1]
JSMethodName:entries[0]
isSync:((NSNumber *)entries[2]).boolValue
moduleClass:_moduleClass];
auto exportedMethod = ((const RCTMethodInfo *(*)(id, SEL))imp)(_moduleClass, selector);
id<RCTBridgeMethod> moduleMethod = [[RCTModuleMethod alloc] initWithExportedMethod:exportedMethod
moduleClass:_moduleClass];
[moduleMethods addObject:moduleMethod];
}
}
@ -345,7 +340,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
}
[syncMethods addObject:@(methods.count)];
}
[methods addObject:method.JSMethodName];
[methods addObject:@(method.JSMethodName)];
}
NSArray *config = @[

View File

@ -10,6 +10,7 @@
#import <Foundation/Foundation.h>
#import <React/RCTBridgeMethod.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTNullability.h>
@class RCTBridge;
@ -27,9 +28,7 @@
@property (nonatomic, readonly) Class moduleClass;
@property (nonatomic, readonly) SEL selector;
- (instancetype)initWithMethodSignature:(NSString *)objCMethodName
JSMethodName:(NSString *)JSMethodName
isSync:(BOOL)isSync
- (instancetype)initWithExportedMethod:(const RCTMethodInfo *)exportMethod
moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER;
@end

View File

@ -41,21 +41,20 @@ typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
@implementation RCTModuleMethod
{
Class _moduleClass;
const RCTMethodInfo *_methodInfo;
NSString *_JSMethodName;
SEL _selector;
NSInvocation *_invocation;
NSArray<RCTArgumentBlock> *_argumentBlocks;
NSString *_methodSignature;
SEL _selector;
BOOL _isSync;
}
@synthesize JSMethodName = _JSMethodName;
static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index,
id valueOrType, const char *issue)
{
RCTLogError(@"Argument %tu (%@) of %@.%@ %s", index, valueOrType,
RCTLogError(@"Argument %tu (%@) of %@.%s %s", index, valueOrType,
RCTBridgeModuleNameForClass(method->_moduleClass),
method->_JSMethodName, issue);
method.JSMethodName, issue);
}
RCT_NOT_IMPLEMENTED(- (instancetype)init)
@ -114,10 +113,9 @@ static BOOL RCTCheckCallbackMultipleInvocations(BOOL *didInvoke) {
}
}
SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **);
SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments)
SEL RCTParseMethodSignature(const char *, NSArray<RCTMethodArgument *> **);
SEL RCTParseMethodSignature(const char *input, NSArray<RCTMethodArgument *> **arguments)
{
const char *input = methodSignature.UTF8String;
RCTSkipWhitespace(&input);
NSMutableArray *args;
@ -164,30 +162,25 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
return NSSelectorFromString(selector);
}
- (instancetype)initWithMethodSignature:(NSString *)methodSignature
JSMethodName:(NSString *)JSMethodName
isSync:(BOOL)isSync
moduleClass:(Class)moduleClass
- (instancetype)initWithExportedMethod:(const RCTMethodInfo *)exportedMethod
moduleClass:(Class)moduleClass
{
if (self = [super init]) {
_moduleClass = moduleClass;
_methodSignature = [methodSignature copy];
_JSMethodName = [JSMethodName copy];
_isSync = isSync;
_methodInfo = exportedMethod;
}
return self;
}
- (void)processMethodSignature
{
NSArray<RCTMethodArgument *> *arguments;
_selector = RCTParseMethodSignature(_methodSignature, &arguments);
RCTAssert(_selector, @"%@ is not a valid selector", _methodSignature);
_selector = RCTParseMethodSignature(_methodInfo->objcName, &arguments);
RCTAssert(_selector, @"%s is not a valid selector", _methodInfo->objcName);
// Create method invocation
NSMethodSignature *methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
RCTAssert(methodSignature, @"%@ is not a recognized Objective-C method.", _methodSignature);
RCTAssert(methodSignature, @"%s is not a recognized Objective-C method.", sel_getName(_selector));
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = _selector;
_invocation = invocation;
@ -328,8 +321,8 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
)
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
RCTAssert(i == numberOfArguments - 2,
@"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]",
_moduleClass, _methodSignature);
@"The RCTPromiseResolveBlock must be the second to last parameter in %@",
[self methodName]);
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise resolver function");
@ -345,8 +338,8 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
)
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
RCTAssert(i == numberOfArguments - 1,
@"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]",
_moduleClass, _methodSignature);
@"The RCTPromiseRejectBlock must be the last parameter in %@",
[self methodName]);
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise rejecter function");
@ -422,9 +415,9 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
if (RCT_DEBUG) {
const char *objcType = _invocation.methodSignature.methodReturnType;
if (_isSync && objcType[0] != _C_ID)
RCTLogError(@"Return type of %@.%@ should be (id) as the method is \"sync\"",
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
if (_methodInfo->isSync && objcType[0] != _C_ID)
RCTLogError(@"Return type of %@.%s should be (id) as the method is \"sync\"",
RCTBridgeModuleNameForClass(_moduleClass), self.JSMethodName);
}
_argumentBlocks = [argumentBlocks copy];
@ -434,36 +427,41 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
{
if (_selector == NULL) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"", (@{ @"module": NSStringFromClass(_moduleClass),
@"method": _methodSignature }));
@"method": @(_methodInfo->objcName) }));
[self processMethodSignature];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
return _selector;
}
- (NSString *)JSMethodName
- (const char *)JSMethodName
{
NSString *methodName = _JSMethodName;
if (methodName.length == 0) {
methodName = _methodSignature;
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location];
if (!methodName) {
const char *jsName = _methodInfo->jsName;
if (jsName && strlen(jsName) > 0) {
methodName = @(jsName);
} else {
methodName = @(_methodInfo->objcName);
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location];
}
methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
RCTAssert(methodName.length, @"%s is not a valid JS function name, please"
" supply an alternative using RCT_REMAP_METHOD()", _methodInfo->objcName);
}
methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
RCTAssert(methodName.length, @"%@ is not a valid JS function name, please"
" supply an alternative using RCT_REMAP_METHOD()", _methodSignature);
_JSMethodName = methodName;
}
return methodName;
return methodName.UTF8String;
}
- (RCTFunctionType)functionType
{
if ([_methodSignature rangeOfString:@"RCTPromise"].length) {
RCTAssert(!_isSync, @"Promises cannot be used in sync functions");
if (strstr(_methodInfo->objcName, "RCTPromise") != NULL) {
RCTAssert(!_methodInfo->isSync, @"Promises cannot be used in sync functions");
return RCTFunctionTypePromise;
} else if (_isSync) {
} else if (_methodInfo->isSync) {
return RCTFunctionTypeSync;
} else {
return RCTFunctionTypeNormal;
@ -494,11 +492,11 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
expectedCount -= 2;
}
RCTLogError(@"%@.%@ was called with %zd arguments but expects %zd arguments. "
RCTLogError(@"%@.%s was called with %zd arguments but expects %zd arguments. "
@"If you haven\'t changed this method yourself, this usually means that "
@"your versions of the native code and JavaScript code are out of sync. "
@"Updating both should make this error go away.",
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
RCTBridgeModuleNameForClass(_moduleClass), self.JSMethodName,
actualCount, expectedCount);
return nil;
}
@ -540,7 +538,7 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
}
id result = nil;
if (_isSync) {
if (_methodInfo->isSync) {
void *pointer;
[_invocation getReturnValue:&pointer];
result = (__bridge id)pointer;
@ -554,13 +552,12 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
if (_selector == NULL) {
[self processMethodSignature];
}
return [NSString stringWithFormat:@"-[%@ %@]", _moduleClass,
NSStringFromSelector(_selector)];
return [NSString stringWithFormat:@"-[%@ %s]", _moduleClass, sel_getName(_selector)];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %@(); type: %s>",
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %s(); type: %s>",
[self class], self, [self methodName], self.JSMethodName, RCTFunctionDescriptorFromType(self.functionType)];
}

View File

@ -26,17 +26,31 @@ using namespace facebook::react;
std::unique_ptr<CxxModule::Method> _method;
}
@synthesize JSMethodName = _JSMethodName;
- (instancetype)initWithCxxMethod:(const CxxModule::Method &)method
{
if ((self = [super init])) {
_JSMethodName = @(method.name.c_str());
_method = folly::make_unique<CxxModule::Method>(method);
}
return self;
}
- (const char *)JSMethodName
{
return _method->name.c_str();
}
- (RCTFunctionType)functionType
{
std::string type(_method->getType());
if (type == "sync") {
return RCTFunctionTypeSync;
} else if (type == "async") {
return RCTFunctionTypeNormal;
} else {
return RCTFunctionTypePromise;
}
}
- (id)invokeWithBridge:(RCTBridge *)bridge
module:(id)module
arguments:(NSArray *)arguments
@ -110,16 +124,9 @@ using namespace facebook::react;
}
}
- (RCTFunctionType)functionType
{
// TODO: support promise-style APIs
return _method->syncFunc ? RCTFunctionTypeSync : RCTFunctionTypeNormal;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; name = %@>",
[self class], self, self.JSMethodName];
return [NSString stringWithFormat:@"<%@: %p; name = %s>", [self class], self, self.JSMethodName];
}
@end

View File

@ -38,7 +38,7 @@ std::vector<MethodDescriptor> RCTNativeModule::getMethods() {
for (id<RCTBridgeMethod> method in m_moduleData.methods) {
descs.emplace_back(
method.JSMethodName.UTF8String,
method.JSMethodName,
RCTFunctionDescriptorFromType(method.functionType)
);
}
@ -103,7 +103,7 @@ MethodCallResult RCTNativeModule::invokeInner(unsigned int methodId, const folly
}
NSString *message = [NSString stringWithFormat:
@"Exception '%@' was thrown while invoking %@ on target %@ with params %@",
@"Exception '%@' was thrown while invoking %s on target %@ with params %@",
exception, method.JSMethodName, m_moduleData.name, objcParams];
RCTFatal(RCTErrorWithMessage(message));
}

View File

@ -68,6 +68,11 @@ public:
std::function<folly::dynamic(folly::dynamic)> syncFunc;
const char *getType() {
assert(func || syncFunc);
return func ? (callbacks == 2 ? "promise" : "async") : "sync";
}
// std::function/lambda ctors
Method(std::string aname,

View File

@ -57,9 +57,7 @@ std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
std::vector<MethodDescriptor> descs;
for (auto& method : methods_) {
assert(method.func || method.syncFunc);
auto methodType = method.func ? (method.callbacks == 2 ? "promise" : "async") : "sync";
descs.emplace_back(method.name, methodType);
descs.emplace_back(method.name, method.getType());
}
return descs;
}