Replaced RegExp method parser with recursive descent

Summary:
public

This diff replaces the RegEx module method parser with a handwritten recursive descent parser that's faster and easier to maintain.

The new parser is ~8 times faster when tested on the UIManager.managerChildren() method, and uses ~1/10 as much RAM.

The new parser also supports lightweight generics, and is more tolerant of white space.

(This means that you now can – and should – use types like `NSArray<NSString *> *` for your exported properties and method arguments, instead of `NSStringArray`).

Reviewed By: jspahrsummers

Differential Revision: D2736636

fb-gh-sync-id: f6a11431935fa8acc8ac36f3471032ec9a1c8490
This commit is contained in:
Nick Lockwood 2015-12-10 10:09:04 -08:00 committed by facebook-github-bot-4
parent ce7c0b735f
commit 88ac40666c
20 changed files with 413 additions and 170 deletions

View File

@ -132,7 +132,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
{ {
__weak RCTModuleMethod *weakMethod; __weak RCTModuleMethod *weakMethod;
@autoreleasepool { @autoreleasepool {
__autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:@"test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d" JSMethodName:@"" moduleClass:[AllocationTestModule class]]; __autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:@"test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d" JSMethodName:@"" moduleClass:[AllocationTestModule class]];
weakMethod = method; weakMethod = method;
XCTAssertNotNil(method, @"RCTModuleMethod should have been created"); XCTAssertNotNil(method, @"RCTModuleMethod should have been created");
} }

View File

@ -23,14 +23,14 @@
@implementation RCTMethodArgumentTests @implementation RCTMethodArgumentTests
extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes); extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes);
- (void)testOneArgument - (void)testOneArgument
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(NSInteger)foo"; NSString *methodSignature = @"foo:(NSInteger)foo";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1); XCTAssertEqual(arguments.count, (NSUInteger)1);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
} }
@ -38,9 +38,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testTwoArguments - (void)testTwoArguments
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(NSInteger)foo bar:(BOOL)bar"; NSString *methodSignature = @"foo:(NSInteger)foo bar:(BOOL)bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -49,9 +49,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testSpaces - (void)testSpaces
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo : (NSInteger)foo bar : (BOOL) bar"; NSString *methodSignature = @"foo : (NSInteger)foo bar : (BOOL) bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -60,9 +60,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testNewlines - (void)testNewlines
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo : (NSInteger)foo\nbar : (BOOL) bar"; NSString *methodSignature = @"foo : (NSInteger)foo\nbar : (BOOL) bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -71,9 +71,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testUnnamedArgs - (void)testUnnamedArgs
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(NSInteger)foo:(BOOL)bar"; NSString *methodSignature = @"foo:(NSInteger)foo:(BOOL)bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo::"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo::");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -82,9 +82,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testUntypedUnnamedArgs - (void)testUntypedUnnamedArgs
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:foo:bar:bar"; NSString *methodSignature = @"foo:foo:bar:bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:::"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:::");
XCTAssertEqual(arguments.count, (NSUInteger)3); XCTAssertEqual(arguments.count, (NSUInteger)3);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"id"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"id");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"id"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"id");
@ -94,9 +94,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testAttributes - (void)testAttributes
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(__attribute__((nonnull)) NSString *)foo bar:(__unused BOOL)bar"; NSString *methodSignature = @"foo:(__attribute__((unused)) NSString *)foo bar:(__unused BOOL)bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -105,9 +105,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testNullability - (void)testNullability
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz"; NSString *methodSignature = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:baz:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:baz:");
XCTAssertEqual(arguments.count, (NSUInteger)3); XCTAssertEqual(arguments.count, (NSUInteger)3);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber");
@ -120,9 +120,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testSemicolonStripping - (void)testSemicolonStripping
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(NSString *)foo bar:(BOOL)bar;"; NSString *methodSignature = @"foo:(NSString *)foo bar:(BOOL)bar;";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@ -131,9 +131,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
- (void)testUnused - (void)testUnused
{ {
NSArray *arguments; NSArray *arguments;
NSString *methodName = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar"; NSString *methodSignature = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar";
RCTParseObjCMethodName(&methodName, &arguments); SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(methodName, @"foo:bar:"); XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqual(arguments.count, (NSUInteger)2);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber");
@ -141,4 +141,44 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes
XCTAssertFalse(((RCTMethodArgument *)arguments[1]).unused); XCTAssertFalse(((RCTMethodArgument *)arguments[1]).unused);
} }
- (void)testGenericArray
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSArray<NSString *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArray");
}
- (void)testNestedGenericArray
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSArray<NSArray<NSString *> *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArrayArray");
}
- (void)testGenericSet
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSSet<NSNumber *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberSet");
}
- (void)testGenericDictionary
{
NSArray *arguments;
NSString *methodSignature = @"foo:(NSDictionary<NSString *, NSNumber *> *)foo;";
SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
XCTAssertEqual(arguments.count, (NSUInteger)1);
XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberDictionary");
}
@end @end

View File

@ -47,8 +47,8 @@ static BOOL RCTLogsError(void (^block)(void))
- (void)testNonnull - (void)testNonnull
{ {
NSString *methodName = @"doFooWithBar:(nonnull NSString *)bar"; NSString *methodSignature = @"doFooWithBar:(nonnull NSString *)bar";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
XCTAssertFalse(RCTLogsError(^{ XCTAssertFalse(RCTLogsError(^{
@ -72,8 +72,8 @@ static BOOL RCTLogsError(void (^block)(void))
{ {
// Specifying an NSNumber param without nonnull isn't allowed // Specifying an NSNumber param without nonnull isn't allowed
XCTAssertTrue(RCTLogsError(^{ XCTAssertTrue(RCTLogsError(^{
NSString *methodName = @"doFooWithNumber:(NSNumber *)n"; NSString *methodSignature = @"doFooWithNumber:(NSNumber *)n";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
// Invoke method to trigger parsing // Invoke method to trigger parsing
@ -82,8 +82,8 @@ static BOOL RCTLogsError(void (^block)(void))
} }
{ {
NSString *methodName = @"doFooWithNumber:(nonnull NSNumber *)n"; NSString *methodSignature = @"doFooWithNumber:(nonnull NSNumber *)n";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
XCTAssertTrue(RCTLogsError(^{ XCTAssertTrue(RCTLogsError(^{
@ -92,8 +92,8 @@ static BOOL RCTLogsError(void (^block)(void))
} }
{ {
NSString *methodName = @"doFooWithDouble:(double)n"; NSString *methodSignature = @"doFooWithDouble:(double)n";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
XCTAssertTrue(RCTLogsError(^{ XCTAssertTrue(RCTLogsError(^{
@ -102,8 +102,8 @@ static BOOL RCTLogsError(void (^block)(void))
} }
{ {
NSString *methodName = @"doFooWithInteger:(NSInteger)n"; NSString *methodSignature = @"doFooWithInteger:(NSInteger)n";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
XCTAssertTrue(RCTLogsError(^{ XCTAssertTrue(RCTLogsError(^{
@ -114,8 +114,8 @@ static BOOL RCTLogsError(void (^block)(void))
- (void)testStructArgument - (void)testStructArgument
{ {
NSString *methodName = @"doFooWithCGRect:(CGRect)s"; NSString *methodSignature = @"doFooWithCGRect:(CGRect)s";
RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
@ -126,11 +126,11 @@ static BOOL RCTLogsError(void (^block)(void))
- (void)testWhitespaceTolerance - (void)testWhitespaceTolerance
{ {
NSString *methodName = @"doFoo : \t (NSString *)foo"; NSString *methodSignature = @"doFoo : \t (NSString *)foo";
__block RCTModuleMethod *method; __block RCTModuleMethod *method;
XCTAssertFalse(RCTLogsError(^{ XCTAssertFalse(RCTLogsError(^{
method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
JSMethodName:nil JSMethodName:nil
moduleClass:[self class]]; moduleClass:[self class]];
})); }));

View File

@ -56,7 +56,7 @@ static NSString *RCTGenerateFormBoundary()
return [[NSString alloc] initWithBytesNoCopy:bytes length:boundaryLength encoding:NSUTF8StringEncoding freeWhenDone:YES]; return [[NSString alloc] initWithBytesNoCopy:bytes length:boundaryLength encoding:NSUTF8StringEncoding freeWhenDone:YES];
} }
- (RCTURLRequestCancellationBlock)process:(NSDictionaryArray *)formData - (RCTURLRequestCancellationBlock)process:(NSArray<NSDictionary *> *)formData
callback:(RCTHTTPQueryResult)callback callback:(RCTHTTPQueryResult)callback
{ {
RCTAssertThread(_networker.methodQueue, @"process: must be called on method queue"); RCTAssertThread(_networker.methodQueue, @"process: must be called on method queue");
@ -289,7 +289,7 @@ RCT_EXPORT_MODULE()
} }
}; };
} }
NSDictionaryArray *formData = [RCTConvert NSDictionaryArray:query[@"formData"]]; NSArray<NSDictionary *> *formData = [RCTConvert NSDictionaryArray:query[@"formData"]];
if (formData) { if (formData) {
RCTHTTPFormDataHelper *formDataHelper = [RCTHTTPFormDataHelper new]; RCTHTTPFormDataHelper *formDataHelper = [RCTHTTPFormDataHelper new];
formDataHelper.networker = self; formDataHelper.networker = self;

View File

@ -90,7 +90,7 @@ RCT_EXPORT_METHOD(setValues:(NSDictionary *)values)
/** /**
* Remove some values from the settings. * Remove some values from the settings.
*/ */
RCT_EXPORT_METHOD(deleteValues:(NSStringArray *)keys) RCT_EXPORT_METHOD(deleteValues:(NSArray<NSString *> *)keys)
{ {
_ignoringUpdates = YES; _ignoringUpdates = YES;
for (NSString *key in keys) { for (NSString *key in keys) {

View File

@ -94,28 +94,13 @@ typedef NSURL RCTFileURL;
size:(id)size weight:(id)weight style:(id)style size:(id)size weight:(id)weight style:(id)style
scaleMultiplier:(CGFloat)scaleMultiplier; scaleMultiplier:(CGFloat)scaleMultiplier;
typedef NSArray NSArrayArray;
+ (NSArray<NSArray *> *)NSArrayArray:(id)json; + (NSArray<NSArray *> *)NSArrayArray:(id)json;
typedef NSArray NSStringArray;
+ (NSArray<NSString *> *)NSStringArray:(id)json; + (NSArray<NSString *> *)NSStringArray:(id)json;
typedef NSArray NSStringArrayArray;
+ (NSArray<NSArray<NSString *> *> *)NSStringArrayArray:(id)json; + (NSArray<NSArray<NSString *> *> *)NSStringArrayArray:(id)json;
typedef NSArray NSDictionaryArray;
+ (NSArray<NSDictionary *> *)NSDictionaryArray:(id)json; + (NSArray<NSDictionary *> *)NSDictionaryArray:(id)json;
typedef NSArray NSURLArray;
+ (NSArray<NSURL *> *)NSURLArray:(id)json; + (NSArray<NSURL *> *)NSURLArray:(id)json;
+ (NSArray<RCTFileURL *> *)RCTFileURLArray:(id)json;
typedef NSArray RCTFileURLArray;
+ (NSArray<NSURL *> *)RCTFileURLArray:(id)json;
typedef NSArray NSNumberArray;
+ (NSArray<NSNumber *> *)NSNumberArray:(id)json; + (NSArray<NSNumber *> *)NSNumberArray:(id)json;
typedef NSArray UIColorArray;
+ (NSArray<UIColor *> *)UIColorArray:(id)json; + (NSArray<UIColor *> *)UIColorArray:(id)json;
typedef NSArray CGColorArray; typedef NSArray CGColorArray;
@ -145,6 +130,18 @@ typedef BOOL css_clip_t, css_backface_visibility_t;
@interface RCTConvert (Deprecated) @interface RCTConvert (Deprecated)
/**
* Use lightweight generics syntax instead, e.g. NSArray<NSString *>
*/
typedef NSArray NSArrayArray __deprecated_msg("Use NSArray<NSArray *>");
typedef NSArray NSStringArray __deprecated_msg("Use NSArray<NSString *>");
typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray<NSArray<NSString *> *>");
typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray<NSDictionary *>");
typedef NSArray NSURLArray __deprecated_msg("Use NSArray<NSURL *>");
typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray<RCTFileURL *>");
typedef NSArray NSNumberArray __deprecated_msg("Use NSArray<NSNumber *>");
typedef NSArray UIColorArray __deprecated_msg("Use NSArray<UIColor *>");
/** /**
* Synchronous image loading is generally a bad idea for performance reasons. * Synchronous image loading is generally a bad idea for performance reasons.
* If you need to pass image references, try to use `RCTImageSource` and then * If you need to pass image references, try to use `RCTImageSource` and then
@ -162,6 +159,11 @@ RCT_EXTERN NSNumber *RCTConvertEnumValue(const char *, NSDictionary *, NSNumber
RCT_EXTERN NSNumber *RCTConvertMultiEnumValue(const char *, NSDictionary *, NSNumber *, id); RCT_EXTERN NSNumber *RCTConvertMultiEnumValue(const char *, NSDictionary *, NSNumber *, id);
RCT_EXTERN NSArray *RCTConvertArrayValue(SEL, id); RCT_EXTERN NSArray *RCTConvertArrayValue(SEL, id);
/**
* Get the converter function for the specified type
*/
RCT_EXTERN SEL RCTConvertSelectorForType(NSString *type);
/** /**
* This macro is used for logging conversion errors. This is just used to * This macro is used for logging conversion errors. This is just used to
* avoid repeating the same boilerplate for every error message. * avoid repeating the same boilerplate for every error message.
@ -238,7 +240,7 @@ RCT_CUSTOM_CONVERTER(type, type, [RCT_DEBUG ? [self NSNumber:json] : json getter
* This macro is used for creating converter functions for typed arrays. * This macro is used for creating converter functions for typed arrays.
*/ */
#define RCT_ARRAY_CONVERTER(type) \ #define RCT_ARRAY_CONVERTER(type) \
+ (NSArray<type *> *)type##Array:(id)json \ + (NSArray<id> *)type##Array:(id)json \
{ \ { \
return RCTConvertArrayValue(@selector(type:), json); \ return RCTConvertArrayValue(@selector(type:), json); \
} }

View File

@ -13,6 +13,7 @@
#import "RCTDefines.h" #import "RCTDefines.h"
#import "RCTImageSource.h" #import "RCTImageSource.h"
#import "RCTParserUtils.h"
#import "RCTUtils.h" #import "RCTUtils.h"
@implementation RCTConvert @implementation RCTConvert
@ -649,6 +650,12 @@ NSArray *RCTConvertArrayValue(SEL type, id json)
return values; return values;
} }
SEL RCTConvertSelectorForType(NSString *type)
{
const char *input = type.UTF8String;
return NSSelectorFromString([RCTParseType(&input) stringByAppendingString:@":"]);
}
RCT_ARRAY_CONVERTER(NSURL) RCT_ARRAY_CONVERTER(NSURL)
RCT_ARRAY_CONVERTER(RCTFileURL) RCT_ARRAY_CONVERTER(RCTFileURL)
RCT_ARRAY_CONVERTER(UIColor) RCT_ARRAY_CONVERTER(UIColor)

View File

@ -122,7 +122,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
NSArray<NSString *> *entries = NSArray<NSString *> *entries =
((NSArray<NSString *> *(*)(id, SEL))imp)(_moduleClass, selector); ((NSArray<NSString *> *(*)(id, SEL))imp)(_moduleClass, selector);
id<RCTBridgeMethod> moduleMethod = id<RCTBridgeMethod> moduleMethod =
[[RCTModuleMethod alloc] initWithObjCMethodName:entries[1] [[RCTModuleMethod alloc] initWithMethodSignature:entries[1]
JSMethodName:entries[0] JSMethodName:entries[0]
moduleClass:_moduleClass]; moduleClass:_moduleClass];

View File

@ -10,15 +10,10 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "RCTBridgeMethod.h" #import "RCTBridgeMethod.h"
#import "RCTNullability.h"
@class RCTBridge; @class RCTBridge;
typedef NS_ENUM(NSUInteger, RCTNullability) {
RCTNullabilityUnspecified,
RCTNullable,
RCTNonnullable,
};
@interface RCTMethodArgument : NSObject @interface RCTMethodArgument : NSObject
@property (nonatomic, copy, readonly) NSString *type; @property (nonatomic, copy, readonly) NSString *type;
@ -32,7 +27,7 @@ typedef NS_ENUM(NSUInteger, RCTNullability) {
@property (nonatomic, readonly) Class moduleClass; @property (nonatomic, readonly) Class moduleClass;
@property (nonatomic, readonly) SEL selector; @property (nonatomic, readonly) SEL selector;
- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName - (instancetype)initWithMethodSignature:(NSString *)objCMethodName
JSMethodName:(NSString *)JSMethodName JSMethodName:(NSString *)JSMethodName
moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER; moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER;

View File

@ -15,6 +15,7 @@
#import "RCTBridge.h" #import "RCTBridge.h"
#import "RCTConvert.h" #import "RCTConvert.h"
#import "RCTLog.h" #import "RCTLog.h"
#import "RCTParserUtils.h"
#import "RCTUtils.h" #import "RCTUtils.h"
typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id); typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
@ -50,7 +51,7 @@ typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
Class _moduleClass; Class _moduleClass;
NSInvocation *_invocation; NSInvocation *_invocation;
NSArray<RCTArgumentBlock> *_argumentBlocks; NSArray<RCTArgumentBlock> *_argumentBlocks;
NSString *_objCMethodName; NSString *_methodSignature;
SEL _selector; SEL _selector;
NSDictionary *_profileArgs; NSDictionary *_profileArgs;
} }
@ -68,77 +69,106 @@ static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index,
RCT_NOT_IMPLEMENTED(- (instancetype)init) RCT_NOT_IMPLEMENTED(- (instancetype)init)
void RCTParseObjCMethodName(NSString **, NSArray<RCTMethodArgument *> **); // returns YES if the selector ends in a colon (indicating that there is at
void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument *> **arguments) // least one argument, and maybe more selector parts) or NO if it doesn't.
static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector)
{ {
static NSRegularExpression *typeNameRegex; NSString *selectorPart;
static dispatch_once_t onceToken; if (RCTParseIdentifier(input, &selectorPart)) {
dispatch_once(&onceToken, ^{ [selector appendString:selectorPart];
NSString *unusedPattern = @"(?:__unused|__attribute__\\(\\(unused\\)\\))"; }
NSString *constPattern = @"(?:const)"; RCTSkipWhitespace(input);
NSString *nullablePattern = @"(?:__nullable|nullable|__attribute__\\(\\(nullable\\)\\))"; if (RCTReadChar(input, ':')) {
NSString *nonnullPattern = @"(?:__nonnull|nonnull|__attribute__\\(\\(nonnull\\)\\))"; [selector appendString:@":"];
NSString *annotationPattern = [NSString stringWithFormat:@"(?:(?:(%@)|%@|(%@)|(%@))\\s*)", RCTSkipWhitespace(input);
unusedPattern, constPattern, nullablePattern, nonnullPattern]; return YES;
NSString *pattern = [NSString stringWithFormat:@"(?<=:)(\\s*\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\))?\\s*\\w+", }
annotationPattern]; return NO;
typeNameRegex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL]; }
});
// Extract argument types static BOOL RCTParseUnused(const char **input)
NSString *methodName = *objCMethodName; {
NSRange methodRange = {0, methodName.length}; return RCTReadString(input, "__unused") ||
NSMutableArray *args = [NSMutableArray array]; RCTReadString(input, "__attribute__((unused))");
[typeNameRegex enumerateMatchesInString:methodName options:0 range:methodRange usingBlock:^(NSTextCheckingResult *result, __unused NSMatchingFlags flags, __unused BOOL *stop) { }
NSRange typeRange = [result rangeAtIndex:5];
NSString *type = typeRange.length ? [methodName substringWithRange:typeRange] : @"id"; static RCTNullability RCTParseNullability(const char **input)
BOOL unused = ([result rangeAtIndex:2].length > 0); {
RCTNullability nullability = [result rangeAtIndex:3].length ? RCTNullable : if (RCTReadString(input, "nullable")) {
[result rangeAtIndex:4].length ? RCTNonnullable : RCTNullabilityUnspecified; return RCTNullable;
} else if (RCTReadString(input, "nonnull")) {
return RCTNonnullable;
}
return RCTNullabilityUnspecified;
}
SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **);
SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments)
{
const char *input = methodSignature.UTF8String;
RCTSkipWhitespace(&input);
NSMutableArray *args;
NSMutableString *selector = [NSMutableString new];
while (RCTParseSelectorPart(&input, selector)) {
if (!args) {
args = [NSMutableArray new];
}
// Parse type
if (RCTReadChar(&input, '(')) {
RCTSkipWhitespace(&input);
BOOL unused = RCTParseUnused(&input);
RCTSkipWhitespace(&input);
RCTNullability nullability = RCTParseNullability(&input);
RCTSkipWhitespace(&input);
NSString *type = RCTParseType(&input);
[args addObject:[[RCTMethodArgument alloc] initWithType:type [args addObject:[[RCTMethodArgument alloc] initWithType:type
nullability:nullability nullability:nullability
unused:unused]]; unused:unused]];
}]; RCTSkipWhitespace(&input);
RCTReadChar(&input, ')');
RCTSkipWhitespace(&input);
} else {
// Type defaults to id if unspecified
[args addObject:[[RCTMethodArgument alloc] initWithType:@"id"
nullability:RCTNullable
unused:NO]];
}
// Argument name
RCTParseIdentifier(&input, NULL);
RCTSkipWhitespace(&input);
}
*arguments = [args copy]; *arguments = [args copy];
return NSSelectorFromString(selector);
// 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; - (instancetype)initWithMethodSignature:(NSString *)methodSignature
}
- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
JSMethodName:(NSString *)JSMethodName JSMethodName:(NSString *)JSMethodName
moduleClass:(Class)moduleClass moduleClass:(Class)moduleClass
{ {
if ((self = [super init])) { if ((self = [super init])) {
_moduleClass = moduleClass; _moduleClass = moduleClass;
_objCMethodName = [objCMethodName copy]; _methodSignature = [methodSignature copy];
_JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({ _JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({
NSString *methodName = objCMethodName; NSString *methodName = methodSignature;
NSRange colonRange = [methodName rangeOfString:@":"]; NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) { if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location]; methodName = [methodName substringToIndex:colonRange.location];
} }
methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
RCTAssert(methodName.length, @"%@ is not a valid JS function name, please" RCTAssert(methodName.length, @"%@ is not a valid JS function name, please"
" supply an alternative using RCT_REMAP_METHOD()", objCMethodName); " supply an alternative using RCT_REMAP_METHOD()", methodSignature);
methodName; methodName;
}); });
if ([_objCMethodName rangeOfString:@"RCTPromise"].length) { if ([_methodSignature rangeOfString:@"RCTPromise"].length) {
_functionType = RCTFunctionTypePromise; _functionType = RCTFunctionTypePromise;
} else { } else {
_functionType = RCTFunctionTypeNormal; _functionType = RCTFunctionTypeNormal;
@ -151,15 +181,12 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument
- (void)processMethodSignature - (void)processMethodSignature
{ {
NSArray<RCTMethodArgument *> *arguments; NSArray<RCTMethodArgument *> *arguments;
NSString *objCMethodName = _objCMethodName; _selector = RCTParseMethodSignature(_methodSignature, &arguments);
RCTParseObjCMethodName(&objCMethodName, &arguments); RCTAssert(_selector, @"%@ is not a valid selector", _methodSignature);
_selector = NSSelectorFromString(objCMethodName);
RCTAssert(_selector, @"%@ is not a valid selector", objCMethodName);
// Create method invocation // Create method invocation
NSMethodSignature *methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector]; NSMethodSignature *methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
RCTAssert(methodSignature, @"%@ is not a recognized Objective-C method.", objCMethodName); RCTAssert(methodSignature, @"%@ is not a recognized Objective-C method.", _methodSignature);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = _selector; invocation.selector = _selector;
_invocation = invocation; _invocation = invocation;
@ -203,7 +230,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument
BOOL isNullableType = NO; BOOL isNullableType = NO;
RCTMethodArgument *argument = arguments[i - 2]; RCTMethodArgument *argument = arguments[i - 2];
NSString *typeName = argument.type; NSString *typeName = argument.type;
SEL selector = NSSelectorFromString([typeName stringByAppendingString:@":"]); SEL selector = RCTConvertSelectorForType(typeName);
if ([RCTConvert respondsToSelector:selector]) { if ([RCTConvert respondsToSelector:selector]) {
switch (objcType[0]) { switch (objcType[0]) {
@ -296,7 +323,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) { } else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
RCTAssert(i == numberOfArguments - 2, RCTAssert(i == numberOfArguments - 2,
@"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]", @"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]",
_moduleClass, objCMethodName); _moduleClass, _methodSignature);
RCT_ARG_BLOCK( RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) { if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise resolver function"); RCTLogArgumentError(weakSelf, index, json, "should be a promise resolver function");
@ -310,7 +337,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) { } else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
RCTAssert(i == numberOfArguments - 1, RCTAssert(i == numberOfArguments - 1,
@"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]", @"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]",
_moduleClass, objCMethodName); _moduleClass, _methodSignature);
RCT_ARG_BLOCK( RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) { if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise rejecter function"); RCTLogArgumentError(weakSelf, index, json, "should be a promise rejecter function");

View File

@ -0,0 +1,16 @@
/**
* 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>
typedef NS_ENUM(NSUInteger, RCTNullability) {
RCTNullabilityUnspecified,
RCTNullable,
RCTNonnullable,
};

View File

@ -0,0 +1,31 @@
/**
* 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>
#import "RCTDefines.h"
@interface RCTParserUtils : NSObject
/**
* Generic utility functions for parsing Objective-C source code.
*/
RCT_EXTERN BOOL RCTReadChar(const char **input, char c);
RCT_EXTERN BOOL RCTReadString(const char **input, const char *string);
RCT_EXTERN void RCTSkipWhitespace(const char **input);
RCT_EXTERN BOOL RCTParseIdentifier(const char **input, NSString **string);
/**
* Parse an Objective-C type into a form that can be used by RCTConvert.
* This doesn't really belong here, but it's used by both RCTConvert and
* RCTModuleMethod, which makes it difficult to find a better home for it.
*/
RCT_EXTERN NSString *RCTParseType(const char **input);
@end

118
React/Base/RCTParserUtils.m Normal file
View File

@ -0,0 +1,118 @@
/**
* 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 "RCTParserUtils.h"
#import "RCTLog.h"
@implementation RCTParserUtils
BOOL RCTReadChar(const char **input, char c)
{
if (**input == c) {
(*input)++;
return YES;
}
return NO;
}
BOOL RCTReadString(const char **input, const char *string)
{
int i;
for (i = 0; string[i] != 0; i++) {
if (string[i] != (*input)[i]) {
return NO;
}
}
*input += i;
return YES;
}
void RCTSkipWhitespace(const char **input)
{
while (isspace(**input)) {
(*input)++;
}
}
static BOOL RCTIsIdentifierHead(const char c)
{
return isalpha(c) || c == '_';
}
static BOOL RCTIsIdentifierTail(const char c)
{
return isalnum(c) || c == '_';
}
BOOL RCTParseIdentifier(const char **input, NSString **string)
{
const char *start = *input;
if (!RCTIsIdentifierHead(**input)) {
return NO;
}
(*input)++;
while (RCTIsIdentifierTail(**input)) {
(*input)++;
}
if (string) {
*string = [[NSString alloc] initWithBytes:start
length:(NSInteger)(*input - start)
encoding:NSASCIIStringEncoding];
}
return YES;
}
static BOOL RCTIsCollectionType(NSString *type)
{
static NSSet *collectionTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
collectionTypes = [[NSSet alloc] initWithObjects:
@"NSArray", @"NSSet", @"NSDictionary", nil];
});
return [collectionTypes containsObject:type];
}
NSString *RCTParseType(const char **input)
{
NSString *type;
RCTParseIdentifier(input, &type);
RCTSkipWhitespace(input);
if (RCTReadChar(input, '<')) {
RCTSkipWhitespace(input);
NSString *subtype = RCTParseType(input);
if (RCTIsCollectionType(type)) {
if ([type isEqualToString:@"NSDictionary"]) {
// Dictionaries have both a key *and* value type, but the key type has
// to be a string for JSON, so we only care about the value type
if (RCT_DEBUG && ![subtype isEqualToString:@"NSString"]) {
RCTLogError(@"%@ is not a valid key type for a JSON dictionary", subtype);
}
RCTSkipWhitespace(input);
RCTReadChar(input, ',');
RCTSkipWhitespace(input);
subtype = RCTParseType(input);
}
if (![subtype isEqualToString:@"id"]) {
type = [type stringByReplacingCharactersInRange:(NSRange){0, 2 /* "NS" */}
withString:subtype];
}
} else {
// It's a protocol rather than a generic collection - ignore it
}
RCTSkipWhitespace(input);
RCTReadChar(input, '>');
}
RCTSkipWhitespace(input);
RCTReadChar(input, '*');
return type;
}
@end

View File

@ -319,7 +319,7 @@ RCT_EXPORT_MODULE()
#pragma mark - Exported JS Functions #pragma mark - Exported JS Functions
RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys RCT_EXPORT_METHOD(multiGet:(NSArray<NSString *> *)keys
callback:(RCTResponseSenderBlock)callback) callback:(RCTResponseSenderBlock)callback)
{ {
NSDictionary *errorOut = [self _ensureSetup]; NSDictionary *errorOut = [self _ensureSetup];
@ -338,7 +338,7 @@ RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys
callback(@[RCTNullIfNil(errors), result]); callback(@[RCTNullIfNil(errors), result]);
} }
RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs RCT_EXPORT_METHOD(multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs
callback:(RCTResponseSenderBlock)callback) callback:(RCTResponseSenderBlock)callback)
{ {
NSDictionary *errorOut = [self _ensureSetup]; NSDictionary *errorOut = [self _ensureSetup];
@ -358,7 +358,7 @@ RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs
callback(@[RCTNullIfNil(errors)]); callback(@[RCTNullIfNil(errors)]);
} }
RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs RCT_EXPORT_METHOD(multiMerge:(NSArray<NSArray<NSString *> *> *)kvPairs
callback:(RCTResponseSenderBlock)callback) callback:(RCTResponseSenderBlock)callback)
{ {
NSDictionary *errorOut = [self _ensureSetup]; NSDictionary *errorOut = [self _ensureSetup];
@ -394,7 +394,7 @@ RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs
callback(@[RCTNullIfNil(errors)]); callback(@[RCTNullIfNil(errors)]);
} }
RCT_EXPORT_METHOD(multiRemove:(NSStringArray *)keys RCT_EXPORT_METHOD(multiRemove:(NSArray<NSString *> *)keys
callback:(RCTResponseSenderBlock)callback) callback:(RCTResponseSenderBlock)callback)
{ {
NSDictionary *errorOut = [self _ensureSetup]; NSDictionary *errorOut = [self _ensureSetup];

View File

@ -34,7 +34,7 @@ RCT_EXPORT_MODULE()
} }
RCT_EXPORT_METHOD(reportSoftException:(NSString *)message RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
stack:(NSDictionaryArray *)stack stack:(NSArray<NSDictionary *> *)stack
exceptionId:(nonnull NSNumber *)exceptionId) exceptionId:(nonnull NSNumber *)exceptionId)
{ {
[_bridge.redBox showErrorMessage:message withStack:stack]; [_bridge.redBox showErrorMessage:message withStack:stack];
@ -45,7 +45,7 @@ RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
} }
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
stack:(NSDictionaryArray *)stack stack:(NSArray<NSDictionary *> *)stack
exceptionId:(nonnull NSNumber *)exceptionId) exceptionId:(nonnull NSNumber *)exceptionId)
{ {
[_bridge.redBox showErrorMessage:message withStack:stack]; [_bridge.redBox showErrorMessage:message withStack:stack];
@ -66,7 +66,7 @@ RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
} }
RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
stack:(NSDictionaryArray *)stack stack:(NSArray<NSDictionary *> *)stack
exceptionId:(nonnull NSNumber *)exceptionId) exceptionId:(nonnull NSNumber *)exceptionId)
{ {
[_bridge.redBox updateErrorMessage:message withStack:stack]; [_bridge.redBox updateErrorMessage:message withStack:stack];
@ -78,7 +78,7 @@ RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
// Deprecated. Use reportFatalException directly instead. // Deprecated. Use reportFatalException directly instead.
RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
stack:(NSDictionaryArray *)stack) stack:(NSArray<NSDictionary *> *)stack)
{ {
[self reportFatalException:message stack:stack exceptionId:@-1]; [self reportFatalException:message stack:stack exceptionId:@-1];
} }

View File

@ -721,11 +721,11 @@ RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag
} }
RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
moveFromIndices:(NSNumberArray *)moveFromIndices moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
moveToIndices:(NSNumberArray *)moveToIndices moveToIndices:(NSArray<NSNumber *> *)moveToIndices
addChildReactTags:(NSNumberArray *)addChildReactTags addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
addAtIndices:(NSNumberArray *)addAtIndices addAtIndices:(NSArray<NSNumber *> *)addAtIndices
removeAtIndices:(NSNumberArray *)removeAtIndices) removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices)
{ {
[self _manageChildren:containerReactTag [self _manageChildren:containerReactTag
moveFromIndices:moveFromIndices moveFromIndices:moveFromIndices

View File

@ -24,6 +24,7 @@
13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; }; 13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; };
13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; }; 13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; };
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; }; 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */; };
13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AB90C01B6FA36700713B4F /* RCTComponentData.m */; }; 13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AB90C01B6FA36700713B4F /* RCTComponentData.m */; };
13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.m */; }; 13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.m */; };
13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */; }; 13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */; };
@ -141,6 +142,9 @@
13A0C2881B74F71200B29F6F /* RCTDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenu.m; sourceTree = "<group>"; }; 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenu.m; sourceTree = "<group>"; };
13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = "<group>"; }; 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = "<group>"; };
13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = "<group>"; }; 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = "<group>"; };
13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTParserUtils.h; sourceTree = "<group>"; };
13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTParserUtils.m; sourceTree = "<group>"; };
13A6E20F1C19ABC700845B82 /* RCTNullability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNullability.h; sourceTree = "<group>"; };
13AB90BF1B6FA36700713B4F /* RCTComponentData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponentData.h; sourceTree = "<group>"; }; 13AB90BF1B6FA36700713B4F /* RCTComponentData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponentData.h; sourceTree = "<group>"; };
13AB90C01B6FA36700713B4F /* RCTComponentData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTComponentData.m; sourceTree = "<group>"; }; 13AB90C01B6FA36700713B4F /* RCTComponentData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTComponentData.m; sourceTree = "<group>"; };
13AF1F851AE6E777005F5298 /* RCTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDefines.h; sourceTree = "<group>"; }; 13AF1F851AE6E777005F5298 /* RCTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDefines.h; sourceTree = "<group>"; };
@ -518,6 +522,9 @@
14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */, 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */,
14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */, 14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */,
14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */, 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */,
13A6E20F1C19ABC700845B82 /* RCTNullability.h */,
13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */,
13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */,
142014181B32094000CC17BA /* RCTPerformanceLogger.h */, 142014181B32094000CC17BA /* RCTPerformanceLogger.h */,
142014171B32094000CC17BA /* RCTPerformanceLogger.m */, 142014171B32094000CC17BA /* RCTPerformanceLogger.m */,
830A229C1A66C68A008503DA /* RCTRootView.h */, 830A229C1A66C68A008503DA /* RCTRootView.h */,
@ -674,6 +681,7 @@
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */, 83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */, 83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */, 13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */,
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */, 13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */, 13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */,
13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */, 13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */,

View File

@ -114,7 +114,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
if ([managerClass respondsToSelector:selector]) { if ([managerClass respondsToSelector:selector]) {
NSArray<NSString *> *typeAndKeyPath = NSArray<NSString *> *typeAndKeyPath =
((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(managerClass, selector); ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(managerClass, selector);
type = NSSelectorFromString([typeAndKeyPath[0] stringByAppendingString:@":"]); type = RCTConvertSelectorForType(typeAndKeyPath[0]);
keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil; keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil;
} else { } else {
propBlock = ^(__unused id view, __unused id json) {}; propBlock = ^(__unused id view, __unused id json) {};

View File

@ -10,7 +10,6 @@
#import "RCTPickerManager.h" #import "RCTPickerManager.h"
#import "RCTBridge.h" #import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTPicker.h" #import "RCTPicker.h"
@implementation RCTPickerManager @implementation RCTPickerManager
@ -22,7 +21,7 @@ RCT_EXPORT_MODULE()
return [RCTPicker new]; return [RCTPicker new];
} }
RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray) RCT_EXPORT_VIEW_PROPERTY(items, NSArray<NSDictionary *>)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger) RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(color, UIColor) RCT_EXPORT_VIEW_PROPERTY(color, UIColor)

View File

@ -22,7 +22,7 @@ RCT_EXPORT_MODULE()
return [RCTSegmentedControl new]; return [RCTSegmentedControl new];
} }
RCT_EXPORT_VIEW_PROPERTY(values, NSStringArray) RCT_EXPORT_VIEW_PROPERTY(values, NSArray<NSString *>)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger) RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(momentary, BOOL) RCT_EXPORT_VIEW_PROPERTY(momentary, BOOL)