[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
/**
|
|
|
|
* 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 "RCTModuleMethod.h"
|
|
|
|
|
|
|
|
#import <objc/message.h>
|
|
|
|
|
2015-07-28 20:09:22 +00:00
|
|
|
#import "RCTAssert.h"
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
#import "RCTBridge.h"
|
|
|
|
#import "RCTConvert.h"
|
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "RCTUtils.h"
|
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
typedef void (^RCTArgumentBlock)(RCTBridge *, NSInvocation *, NSUInteger, id);
|
|
|
|
|
|
|
|
@implementation RCTMethodArgument
|
|
|
|
|
|
|
|
- (instancetype)initWithType:(NSString *)type
|
|
|
|
nullability:(RCTNullability)nullability
|
2015-07-31 13:55:47 +00:00
|
|
|
unused:(BOOL)unused
|
2015-07-29 12:54:59 +00:00
|
|
|
{
|
|
|
|
if ((self = [super init])) {
|
|
|
|
_type = [type copy];
|
|
|
|
_nullability = nullability;
|
2015-07-31 13:55:47 +00:00
|
|
|
_unused = unused;
|
2015-07-29 12:54:59 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
@interface RCTBridge (RCTModuleMethod)
|
|
|
|
|
|
|
|
- (void)_invokeAndProcessModule:(NSString *)module
|
|
|
|
method:(NSString *)method
|
|
|
|
arguments:(NSArray *)args;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RCTModuleMethod
|
|
|
|
{
|
|
|
|
Class _moduleClass;
|
|
|
|
SEL _selector;
|
|
|
|
NSMethodSignature *_methodSignature;
|
|
|
|
NSArray *_argumentBlocks;
|
|
|
|
}
|
|
|
|
|
2015-07-09 23:45:48 +00:00
|
|
|
RCT_NOT_IMPLEMENTED(-init)
|
|
|
|
|
2015-07-28 20:09:22 +00:00
|
|
|
void RCTParseObjCMethodName(NSString **, NSArray **);
|
2015-07-29 12:54:59 +00:00
|
|
|
void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
|
2015-07-28 20:09:22 +00:00
|
|
|
{
|
|
|
|
static NSRegularExpression *typeNameRegex;
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
NSString *unusedPattern = @"(?:__unused|__attribute__\\(\\(unused\\)\\))";
|
|
|
|
NSString *constPattern = @"(?:const)";
|
2015-07-29 12:54:59 +00:00
|
|
|
NSString *nullablePattern = @"(?:__nullable|nullable|__attribute__\\(\\(nullable\\)\\))";
|
|
|
|
NSString *nonnullPattern = @"(?:__nonnull|nonnull|__attribute__\\(\\(nonnull\\)\\))";
|
2015-07-31 13:55:47 +00:00
|
|
|
NSString *annotationPattern = [NSString stringWithFormat:@"(?:(?:(%@)|%@|(%@)|(%@))\\s*)",
|
2015-07-29 12:54:59 +00:00
|
|
|
unusedPattern, constPattern, nullablePattern, nonnullPattern];
|
2015-07-28 20:09:22 +00:00
|
|
|
NSString *pattern = [NSString stringWithFormat:@"(?<=:)(\\s*\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\))?\\s*\\w+",
|
|
|
|
annotationPattern];
|
|
|
|
typeNameRegex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
|
|
|
|
});
|
|
|
|
|
|
|
|
// Extract argument types
|
|
|
|
NSString *methodName = *objCMethodName;
|
|
|
|
NSRange methodRange = {0, methodName.length};
|
2015-07-29 12:54:59 +00:00
|
|
|
NSMutableArray *args = [NSMutableArray array];
|
2015-07-28 20:09:22 +00:00
|
|
|
[typeNameRegex enumerateMatchesInString:methodName options:0 range:methodRange usingBlock:^(NSTextCheckingResult *result, __unused NSMatchingFlags flags, __unused BOOL *stop) {
|
2015-07-31 13:55:47 +00:00
|
|
|
NSRange typeRange = [result rangeAtIndex:5];
|
2015-07-29 12:54:59 +00:00
|
|
|
NSString *type = typeRange.length ? [methodName substringWithRange:typeRange] : @"id";
|
2015-07-31 13:55:47 +00:00
|
|
|
BOOL unused = ([result rangeAtIndex:2].length > 0);
|
|
|
|
RCTNullability nullability = [result rangeAtIndex:3].length ? RCTNullable :
|
|
|
|
[result rangeAtIndex:4].length ? RCTNonnullable : RCTNullabilityUnspecified;
|
|
|
|
[args addObject:[[RCTMethodArgument alloc] initWithType:type
|
|
|
|
nullability:nullability
|
|
|
|
unused:unused]];
|
2015-07-28 20:09:22 +00:00
|
|
|
}];
|
2015-07-29 12:54:59 +00:00
|
|
|
*arguments = [args copy];
|
2015-07-28 20:09:22 +00:00
|
|
|
|
|
|
|
// Remove the parameter types and names
|
|
|
|
methodName = [typeNameRegex stringByReplacingMatchesInString:methodName options:0
|
|
|
|
range:methodRange
|
|
|
|
withTemplate:@""];
|
|
|
|
|
|
|
|
// Remove whitespace
|
|
|
|
methodName = [methodName stringByReplacingOccurrencesOfString:@"\n" withString:@""];
|
|
|
|
methodName = [methodName stringByReplacingOccurrencesOfString:@" " withString:@""];
|
|
|
|
|
|
|
|
// Strip trailing semicolon
|
|
|
|
if ([methodName hasSuffix:@";"]) {
|
|
|
|
methodName = [methodName substringToIndex:methodName.length - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
*objCMethodName = methodName;
|
|
|
|
}
|
|
|
|
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
|
|
|
|
JSMethodName:(NSString *)JSMethodName
|
|
|
|
moduleClass:(Class)moduleClass
|
|
|
|
{
|
|
|
|
if ((self = [super init])) {
|
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
NSArray *arguments;
|
|
|
|
RCTParseObjCMethodName(&objCMethodName, &arguments);
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
|
|
|
|
_moduleClass = moduleClass;
|
|
|
|
_selector = NSSelectorFromString(objCMethodName);
|
2015-07-28 20:09:22 +00:00
|
|
|
RCTAssert(_selector, @"%@ is not a valid selector", objCMethodName);
|
|
|
|
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
_JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({
|
2015-07-28 20:09:22 +00:00
|
|
|
NSString *methodName = objCMethodName;
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
NSRange colonRange = [methodName rangeOfString:@":"];
|
2015-07-28 20:09:22 +00:00
|
|
|
if (colonRange.location != NSNotFound) {
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
methodName = [methodName substringToIndex:colonRange.location];
|
|
|
|
}
|
2015-07-28 20:09:22 +00:00
|
|
|
RCTAssert(methodName.length, @"%@ is not a valid JS function name, please"
|
|
|
|
" supply an alternative using RCT_REMAP_METHOD()", objCMethodName);
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
methodName;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get method signature
|
|
|
|
_methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
|
|
|
|
|
|
|
|
// Process arguments
|
|
|
|
NSUInteger numberOfArguments = _methodSignature.numberOfArguments;
|
|
|
|
NSMutableArray *argumentBlocks = [[NSMutableArray alloc] initWithCapacity:numberOfArguments - 2];
|
|
|
|
|
|
|
|
#define RCT_ARG_BLOCK(_logic) \
|
2015-07-14 23:16:21 +00:00
|
|
|
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
_logic \
|
2015-07-29 12:54:59 +00:00
|
|
|
[invocation setArgument:&value atIndex:(index) + 2]; \
|
2015-07-24 16:34:18 +00:00
|
|
|
}];
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
|
|
|
|
void (^addBlockArgument)(void) = ^{
|
|
|
|
RCT_ARG_BLOCK(
|
|
|
|
|
|
|
|
if (RCT_DEBUG && json && ![json isKindOfClass:[NSNumber class]]) {
|
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
|
|
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
|
|
|
__autoreleasing id value = (json ? ^(NSArray *args) {
|
|
|
|
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
|
|
|
method:@"invokeCallbackAndReturnFlushedQueue"
|
|
|
|
arguments:@[json, args]];
|
|
|
|
} : ^(__unused NSArray *unused) {});
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
for (NSUInteger i = 2; i < numberOfArguments; i++) {
|
2015-07-29 12:54:59 +00:00
|
|
|
const char *objcType = [_methodSignature getArgumentTypeAtIndex:i];
|
2015-07-31 13:55:47 +00:00
|
|
|
BOOL isNullableType = NO;
|
2015-07-29 12:54:59 +00:00
|
|
|
RCTMethodArgument *argument = arguments[i - 2];
|
|
|
|
NSString *typeName = argument.type;
|
|
|
|
SEL selector = NSSelectorFromString([typeName stringByAppendingString:@":"]);
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
if ([RCTConvert respondsToSelector:selector]) {
|
2015-07-29 12:54:59 +00:00
|
|
|
switch (objcType[0]) {
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
|
|
|
|
#define RCT_CONVERT_CASE(_value, _type) \
|
|
|
|
case _value: { \
|
2015-07-31 13:55:47 +00:00
|
|
|
if (RCT_DEBUG && ([@#_type hasSuffix:@"*"] || [@#_type hasSuffix:@"Ref"] || [@#_type isEqualToString:@"id"])) { \
|
|
|
|
isNullableType = YES; \
|
|
|
|
} \
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
_type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \
|
|
|
|
RCT_ARG_BLOCK( _type value = convert([RCTConvert class], selector, json); ) \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
RCT_CONVERT_CASE(':', SEL)
|
|
|
|
RCT_CONVERT_CASE('*', const char *)
|
|
|
|
RCT_CONVERT_CASE('c', char)
|
|
|
|
RCT_CONVERT_CASE('C', unsigned char)
|
|
|
|
RCT_CONVERT_CASE('s', short)
|
|
|
|
RCT_CONVERT_CASE('S', unsigned short)
|
|
|
|
RCT_CONVERT_CASE('i', int)
|
|
|
|
RCT_CONVERT_CASE('I', unsigned int)
|
|
|
|
RCT_CONVERT_CASE('l', long)
|
|
|
|
RCT_CONVERT_CASE('L', unsigned long)
|
|
|
|
RCT_CONVERT_CASE('q', long long)
|
|
|
|
RCT_CONVERT_CASE('Q', unsigned long long)
|
|
|
|
RCT_CONVERT_CASE('f', float)
|
|
|
|
RCT_CONVERT_CASE('d', double)
|
|
|
|
RCT_CONVERT_CASE('B', BOOL)
|
|
|
|
RCT_CONVERT_CASE('@', id)
|
|
|
|
RCT_CONVERT_CASE('^', void *)
|
|
|
|
|
|
|
|
case '{': {
|
|
|
|
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) {
|
2015-07-31 13:55:47 +00:00
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
NSMethodSignature *methodSignature = [RCTConvert methodSignatureForSelector:selector];
|
|
|
|
void *returnValue = malloc(methodSignature.methodReturnLength);
|
|
|
|
NSInvocation *_invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
|
|
|
[_invocation setTarget:[RCTConvert class]];
|
|
|
|
[_invocation setSelector:selector];
|
|
|
|
[_invocation setArgument:&json atIndex:2];
|
|
|
|
[_invocation invoke];
|
|
|
|
[_invocation getReturnValue:returnValue];
|
|
|
|
|
|
|
|
[invocation setArgument:returnValue atIndex:index + 2];
|
|
|
|
|
|
|
|
free(returnValue);
|
|
|
|
}];
|
|
|
|
break;
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
}
|
2015-07-07 15:47:23 +00:00
|
|
|
|
2015-07-31 13:55:47 +00:00
|
|
|
default: {
|
|
|
|
static const char *blockType = @encode(typeof(^{}));
|
|
|
|
if (!strcmp(objcType, blockType)) {
|
|
|
|
addBlockArgument();
|
|
|
|
} else {
|
|
|
|
RCTLogError(@"Unsupported argument type '%@' in method %@.",
|
|
|
|
typeName, [self methodName]);
|
|
|
|
}
|
|
|
|
}
|
2015-07-29 12:54:59 +00:00
|
|
|
}
|
|
|
|
} else if ([typeName isEqualToString:@"RCTResponseSenderBlock"]) {
|
|
|
|
addBlockArgument();
|
|
|
|
} else if ([typeName isEqualToString:@"RCTResponseErrorBlock"]) {
|
|
|
|
RCT_ARG_BLOCK(
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
if (RCT_DEBUG && json && ![json isKindOfClass:[NSNumber class]]) {
|
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
|
|
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
|
|
|
__autoreleasing id value = (json ? ^(NSError *error) {
|
|
|
|
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
|
|
|
method:@"invokeCallbackAndReturnFlushedQueue"
|
|
|
|
arguments:@[json, @[RCTJSErrorFromNSError(error)]]];
|
|
|
|
} : ^(__unused NSError *error) {});
|
|
|
|
)
|
|
|
|
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
|
|
|
|
RCTAssert(i == numberOfArguments - 2,
|
|
|
|
@"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]",
|
|
|
|
_moduleClass, objCMethodName);
|
|
|
|
RCT_ARG_BLOCK(
|
|
|
|
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
|
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ must be a promise resolver ID", index,
|
|
|
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
|
|
|
__autoreleasing RCTPromiseResolveBlock value = (^(id result) {
|
|
|
|
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
|
|
|
method:@"invokeCallbackAndReturnFlushedQueue"
|
|
|
|
arguments:@[json, result ? @[result] : @[]]];
|
|
|
|
});
|
|
|
|
)
|
|
|
|
_functionKind = RCTJavaScriptFunctionKindAsync;
|
|
|
|
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
|
|
|
|
RCTAssert(i == numberOfArguments - 1,
|
|
|
|
@"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]",
|
|
|
|
_moduleClass, objCMethodName);
|
|
|
|
RCT_ARG_BLOCK(
|
|
|
|
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
|
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ must be a promise rejecter ID", index,
|
|
|
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
|
|
|
return;
|
|
|
|
}
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
|
|
|
__autoreleasing RCTPromiseRejectBlock value = (^(NSError *error) {
|
|
|
|
NSDictionary *errorJSON = RCTJSErrorFromNSError(error);
|
|
|
|
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
|
|
|
method:@"invokeCallbackAndReturnFlushedQueue"
|
|
|
|
arguments:@[json, @[errorJSON]]];
|
|
|
|
});
|
|
|
|
)
|
|
|
|
_functionKind = RCTJavaScriptFunctionKindAsync;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Unknown argument type
|
|
|
|
RCTLogError(@"Unknown argument type '%@' in method %@. Extend RCTConvert"
|
2015-07-31 13:55:47 +00:00
|
|
|
" to support this type.", typeName, [self methodName]);
|
2015-07-29 12:54:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RCT_DEBUG) {
|
2015-07-31 13:55:47 +00:00
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
RCTNullability nullability = argument.nullability;
|
2015-07-31 13:55:47 +00:00
|
|
|
if (!isNullableType) {
|
|
|
|
if (nullability == RCTNullable) {
|
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ is marked as nullable, but "
|
|
|
|
"is not a nullable type.", i - 2, typeName,
|
|
|
|
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
|
|
|
}
|
|
|
|
nullability = RCTNonnullable;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Special case - Numbers are not nullable in Android, so we
|
|
|
|
* don't support this for now. In future we may allow it.
|
|
|
|
*/
|
|
|
|
if ([typeName isEqualToString:@"NSNumber"]) {
|
|
|
|
BOOL unspecified = (nullability == RCTNullabilityUnspecified);
|
|
|
|
if (!argument.unused && (nullability == RCTNullable || unspecified)) {
|
|
|
|
RCTLogError(@"Argument %tu (NSNumber) of %@.%@ %@, but React requires "
|
|
|
|
"that all NSNumber arguments are explicitly marked as "
|
|
|
|
"`nonnull` to ensure compatibility with Android.", i - 2,
|
|
|
|
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
|
|
|
|
unspecified ? @"has unspecified nullability" : @"is marked as nullable");
|
|
|
|
}
|
|
|
|
nullability = RCTNonnullable;
|
|
|
|
}
|
|
|
|
|
2015-07-29 12:54:59 +00:00
|
|
|
if (nullability == RCTNonnullable) {
|
|
|
|
RCTArgumentBlock oldBlock = argumentBlocks[i - 2];
|
|
|
|
argumentBlocks[i - 2] = ^(RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) {
|
|
|
|
if (json == nil || json == (id)kCFNull) {
|
2015-07-31 13:55:47 +00:00
|
|
|
RCTLogError(@"Argument %tu (%@) of %@.%@ must not be null", index,
|
|
|
|
typeName, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
2015-07-29 12:54:59 +00:00
|
|
|
id null = nil;
|
|
|
|
[invocation setArgument:&null atIndex:index + 2];
|
|
|
|
} else {
|
|
|
|
oldBlock(bridge, invocation, index, json);
|
|
|
|
}
|
|
|
|
};
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
}
|
2015-07-29 12:54:59 +00:00
|
|
|
}
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_argumentBlocks = [argumentBlocks copy];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)invokeWithBridge:(RCTBridge *)bridge
|
|
|
|
module:(id)module
|
|
|
|
arguments:(NSArray *)arguments
|
|
|
|
{
|
|
|
|
if (RCT_DEBUG) {
|
|
|
|
|
|
|
|
// Sanity check
|
|
|
|
RCTAssert([module class] == _moduleClass, @"Attempted to invoke method \
|
|
|
|
%@ on a module of class %@", [self methodName], [module class]);
|
|
|
|
|
|
|
|
// Safety check
|
|
|
|
if (arguments.count != _argumentBlocks.count) {
|
|
|
|
NSInteger actualCount = arguments.count;
|
|
|
|
NSInteger expectedCount = _argumentBlocks.count;
|
|
|
|
|
|
|
|
// Subtract the implicit Promise resolver and rejecter functions for implementations of async functions
|
|
|
|
if (_functionKind == RCTJavaScriptFunctionKindAsync) {
|
|
|
|
actualCount -= 2;
|
|
|
|
expectedCount -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd",
|
|
|
|
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
|
|
|
|
actualCount, expectedCount);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create invocation (we can't re-use this as it wouldn't be thread-safe)
|
|
|
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:_methodSignature];
|
|
|
|
[invocation setArgument:&_selector atIndex:1];
|
|
|
|
[invocation retainArguments];
|
|
|
|
|
|
|
|
// Set arguments
|
|
|
|
NSUInteger index = 0;
|
|
|
|
for (id json in arguments) {
|
|
|
|
id arg = RCTNilIfNull(json);
|
2015-07-29 12:54:59 +00:00
|
|
|
RCTArgumentBlock block = _argumentBlocks[index];
|
|
|
|
block(bridge, invocation, index, arg);
|
[ReactNative] Move module info from bridge to RCTModuleData
Summary:
@public
The info about bridge modules (such as id, name, queue, methods...) was spread
across arrays & dictionaries on the bridge, move it into a specific class.
It also removes a lot of information that was statically cached, and now have
the same lifecycle of the bridge.
Also moved RCTModuleMethod, RCTFrameUpdate and RCTBatchedBridge into it's own
files, for organization sake.
NOTE: This diff seems huge, but most of it was just moving code :)
Test Plan:
Tested UIExplorer & UIExplorer tests, Catalyst, MAdMan and Groups. Everything
looks fine.
2015-06-24 23:34:56 +00:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoke method
|
|
|
|
[invocation invokeWithTarget:module];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)methodName
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat:@"-[%@ %@]", _moduleClass,
|
|
|
|
NSStringFromSelector(_selector)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)description
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %@();>",
|
|
|
|
[self class], self, [self methodName], _JSMethodName];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|