diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m index 4fe7294fb3..239973ca03 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m @@ -132,7 +132,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a { __weak RCTModuleMethod *weakMethod; @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; XCTAssertNotNil(method, @"RCTModuleMethod should have been created"); } diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m index 3f53812473..53d9d0f743 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m @@ -23,14 +23,14 @@ @implementation RCTMethodArgumentTests -extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes); +extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes); - (void)testOneArgument { NSArray *arguments; - NSString *methodName = @"foo:(NSInteger)foo"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:"); + NSString *methodSignature = @"foo:(NSInteger)foo"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:"); XCTAssertEqual(arguments.count, (NSUInteger)1); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); } @@ -38,9 +38,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testTwoArguments { NSArray *arguments; - NSString *methodName = @"foo:(NSInteger)foo bar:(BOOL)bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *methodSignature = @"foo:(NSInteger)foo bar:(BOOL)bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -49,9 +49,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testSpaces { NSArray *arguments; - NSString *methodName = @"foo : (NSInteger)foo bar : (BOOL) bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *methodSignature = @"foo : (NSInteger)foo bar : (BOOL) bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -60,9 +60,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testNewlines { NSArray *arguments; - NSString *methodName = @"foo : (NSInteger)foo\nbar : (BOOL) bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *methodSignature = @"foo : (NSInteger)foo\nbar : (BOOL) bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -71,9 +71,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testUnnamedArgs { NSArray *arguments; - NSString *methodName = @"foo:(NSInteger)foo:(BOOL)bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo::"); + NSString *methodSignature = @"foo:(NSInteger)foo:(BOOL)bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo::"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -82,9 +82,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testUntypedUnnamedArgs { NSArray *arguments; - NSString *methodName = @"foo:foo:bar:bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:::"); + NSString *methodSignature = @"foo:foo:bar:bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:::"); XCTAssertEqual(arguments.count, (NSUInteger)3); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"id"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"id"); @@ -94,9 +94,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testAttributes { NSArray *arguments; - NSString *methodName = @"foo:(__attribute__((nonnull)) NSString *)foo bar:(__unused BOOL)bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *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); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -105,9 +105,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testNullability { NSArray *arguments; - NSString *methodName = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:baz:"); + NSString *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); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); @@ -120,9 +120,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testSemicolonStripping { NSArray *arguments; - NSString *methodName = @"foo:(NSString *)foo bar:(BOOL)bar;"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *methodSignature = @"foo:(NSString *)foo bar:(BOOL)bar;"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL"); @@ -131,9 +131,9 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes - (void)testUnused { NSArray *arguments; - NSString *methodName = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar"; - RCTParseObjCMethodName(&methodName, &arguments); - XCTAssertEqualObjects(methodName, @"foo:bar:"); + NSString *methodSignature = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:"); XCTAssertEqual(arguments.count, (NSUInteger)2); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString"); XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber"); @@ -141,4 +141,44 @@ extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes XCTAssertFalse(((RCTMethodArgument *)arguments[1]).unused); } +- (void)testGenericArray +{ + NSArray *arguments; + NSString *methodSignature = @"foo:(NSArray *)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 *> *)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 *)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 *)foo;"; + SEL selector = RCTParseMethodSignature(methodSignature, &arguments); + XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:"); + XCTAssertEqual(arguments.count, (NSUInteger)1); + XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberDictionary"); +} + @end diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m index 93ac3b5aa0..f247da4ffc 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m @@ -47,10 +47,10 @@ static BOOL RCTLogsError(void (^block)(void)) - (void)testNonnull { - NSString *methodName = @"doFooWithBar:(nonnull NSString *)bar"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithBar:(nonnull NSString *)bar"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; XCTAssertFalse(RCTLogsError(^{ [method invokeWithBridge:nil module:self arguments:@[@"Hello World"]]; })); @@ -72,40 +72,40 @@ static BOOL RCTLogsError(void (^block)(void)) { // Specifying an NSNumber param without nonnull isn't allowed XCTAssertTrue(RCTLogsError(^{ - NSString *methodName = @"doFooWithNumber:(NSNumber *)n"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithNumber:(NSNumber *)n"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; // Invoke method to trigger parsing [method invokeWithBridge:nil module:self arguments:@[@1]]; })); } { - NSString *methodName = @"doFooWithNumber:(nonnull NSNumber *)n"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithNumber:(nonnull NSNumber *)n"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; XCTAssertTrue(RCTLogsError(^{ [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]]; })); } { - NSString *methodName = @"doFooWithDouble:(double)n"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithDouble:(double)n"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; XCTAssertTrue(RCTLogsError(^{ [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]]; })); } { - NSString *methodName = @"doFooWithInteger:(NSInteger)n"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithInteger:(NSInteger)n"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; XCTAssertTrue(RCTLogsError(^{ [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]]; })); @@ -114,10 +114,10 @@ static BOOL RCTLogsError(void (^block)(void)) - (void)testStructArgument { - NSString *methodName = @"doFooWithCGRect:(CGRect)s"; - RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + NSString *methodSignature = @"doFooWithCGRect:(CGRect)s"; + RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; CGRect r = CGRectMake(10, 20, 30, 40); [method invokeWithBridge:nil module:self arguments:@[@[@10, @20, @30, @40]]]; @@ -126,13 +126,13 @@ static BOOL RCTLogsError(void (^block)(void)) - (void)testWhitespaceTolerance { - NSString *methodName = @"doFoo : \t (NSString *)foo"; + NSString *methodSignature = @"doFoo : \t (NSString *)foo"; __block RCTModuleMethod *method; XCTAssertFalse(RCTLogsError(^{ - method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName - JSMethodName:nil - moduleClass:[self class]]; + method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + moduleClass:[self class]]; })); XCTAssertEqualObjects(method.JSMethodName, @"doFoo"); diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m index 9afb0914ee..0c5aeaecd7 100644 --- a/Libraries/Network/RCTNetworking.m +++ b/Libraries/Network/RCTNetworking.m @@ -56,7 +56,7 @@ static NSString *RCTGenerateFormBoundary() return [[NSString alloc] initWithBytesNoCopy:bytes length:boundaryLength encoding:NSUTF8StringEncoding freeWhenDone:YES]; } -- (RCTURLRequestCancellationBlock)process:(NSDictionaryArray *)formData +- (RCTURLRequestCancellationBlock)process:(NSArray *)formData callback:(RCTHTTPQueryResult)callback { RCTAssertThread(_networker.methodQueue, @"process: must be called on method queue"); @@ -289,7 +289,7 @@ RCT_EXPORT_MODULE() } }; } - NSDictionaryArray *formData = [RCTConvert NSDictionaryArray:query[@"formData"]]; + NSArray *formData = [RCTConvert NSDictionaryArray:query[@"formData"]]; if (formData) { RCTHTTPFormDataHelper *formDataHelper = [RCTHTTPFormDataHelper new]; formDataHelper.networker = self; diff --git a/Libraries/Settings/RCTSettingsManager.m b/Libraries/Settings/RCTSettingsManager.m index 2ff4f3b4d7..c0c915df77 100644 --- a/Libraries/Settings/RCTSettingsManager.m +++ b/Libraries/Settings/RCTSettingsManager.m @@ -90,7 +90,7 @@ RCT_EXPORT_METHOD(setValues:(NSDictionary *)values) /** * Remove some values from the settings. */ -RCT_EXPORT_METHOD(deleteValues:(NSStringArray *)keys) +RCT_EXPORT_METHOD(deleteValues:(NSArray *)keys) { _ignoringUpdates = YES; for (NSString *key in keys) { diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 6347cc9cab..231f888c48 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -94,28 +94,13 @@ typedef NSURL RCTFileURL; size:(id)size weight:(id)weight style:(id)style scaleMultiplier:(CGFloat)scaleMultiplier; -typedef NSArray NSArrayArray; + (NSArray *)NSArrayArray:(id)json; - -typedef NSArray NSStringArray; + (NSArray *)NSStringArray:(id)json; - -typedef NSArray NSStringArrayArray; + (NSArray *> *)NSStringArrayArray:(id)json; - -typedef NSArray NSDictionaryArray; + (NSArray *)NSDictionaryArray:(id)json; - -typedef NSArray NSURLArray; + (NSArray *)NSURLArray:(id)json; - -typedef NSArray RCTFileURLArray; -+ (NSArray *)RCTFileURLArray:(id)json; - -typedef NSArray NSNumberArray; ++ (NSArray *)RCTFileURLArray:(id)json; + (NSArray *)NSNumberArray:(id)json; - -typedef NSArray UIColorArray; + (NSArray *)UIColorArray:(id)json; typedef NSArray CGColorArray; @@ -145,6 +130,18 @@ typedef BOOL css_clip_t, css_backface_visibility_t; @interface RCTConvert (Deprecated) +/** + * Use lightweight generics syntax instead, e.g. NSArray + */ +typedef NSArray NSArrayArray __deprecated_msg("Use NSArray"); +typedef NSArray NSStringArray __deprecated_msg("Use NSArray"); +typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray *>"); +typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray"); +typedef NSArray NSURLArray __deprecated_msg("Use NSArray"); +typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray"); +typedef NSArray NSNumberArray __deprecated_msg("Use NSArray"); +typedef NSArray UIColorArray __deprecated_msg("Use NSArray"); + /** * Synchronous image loading is generally a bad idea for performance reasons. * 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 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 * 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. */ #define RCT_ARRAY_CONVERTER(type) \ -+ (NSArray *)type##Array:(id)json \ ++ (NSArray *)type##Array:(id)json \ { \ return RCTConvertArrayValue(@selector(type:), json); \ } diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 244fe6c0af..5860bbc597 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -13,6 +13,7 @@ #import "RCTDefines.h" #import "RCTImageSource.h" +#import "RCTParserUtils.h" #import "RCTUtils.h" @implementation RCTConvert @@ -649,6 +650,12 @@ NSArray *RCTConvertArrayValue(SEL type, id json) return values; } +SEL RCTConvertSelectorForType(NSString *type) +{ + const char *input = type.UTF8String; + return NSSelectorFromString([RCTParseType(&input) stringByAppendingString:@":"]); +} + RCT_ARRAY_CONVERTER(NSURL) RCT_ARRAY_CONVERTER(RCTFileURL) RCT_ARRAY_CONVERTER(UIColor) diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m index b8fa170490..d254509a76 100644 --- a/React/Base/RCTModuleData.m +++ b/React/Base/RCTModuleData.m @@ -122,9 +122,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init); NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); id moduleMethod = - [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1] - JSMethodName:entries[0] - moduleClass:_moduleClass]; + [[RCTModuleMethod alloc] initWithMethodSignature:entries[1] + JSMethodName:entries[0] + moduleClass:_moduleClass]; [moduleMethods addObject:moduleMethod]; } diff --git a/React/Base/RCTModuleMethod.h b/React/Base/RCTModuleMethod.h index f450c412ce..5572dba3a3 100644 --- a/React/Base/RCTModuleMethod.h +++ b/React/Base/RCTModuleMethod.h @@ -10,15 +10,10 @@ #import #import "RCTBridgeMethod.h" +#import "RCTNullability.h" @class RCTBridge; -typedef NS_ENUM(NSUInteger, RCTNullability) { - RCTNullabilityUnspecified, - RCTNullable, - RCTNonnullable, -}; - @interface RCTMethodArgument : NSObject @property (nonatomic, copy, readonly) NSString *type; @@ -32,7 +27,7 @@ typedef NS_ENUM(NSUInteger, RCTNullability) { @property (nonatomic, readonly) Class moduleClass; @property (nonatomic, readonly) SEL selector; -- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName +- (instancetype)initWithMethodSignature:(NSString *)objCMethodName JSMethodName:(NSString *)JSMethodName moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER; diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m index 0182fe93d8..407fed3dab 100644 --- a/React/Base/RCTModuleMethod.m +++ b/React/Base/RCTModuleMethod.m @@ -15,6 +15,7 @@ #import "RCTBridge.h" #import "RCTConvert.h" #import "RCTLog.h" +#import "RCTParserUtils.h" #import "RCTUtils.h" typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id); @@ -50,7 +51,7 @@ typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id); Class _moduleClass; NSInvocation *_invocation; NSArray *_argumentBlocks; - NSString *_objCMethodName; + NSString *_methodSignature; SEL _selector; NSDictionary *_profileArgs; } @@ -68,77 +69,106 @@ static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index, RCT_NOT_IMPLEMENTED(- (instancetype)init) -void RCTParseObjCMethodName(NSString **, NSArray **); -void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments) +// returns YES if the selector ends in a colon (indicating that there is at +// 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; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSString *unusedPattern = @"(?:__unused|__attribute__\\(\\(unused\\)\\))"; - NSString *constPattern = @"(?:const)"; - NSString *nullablePattern = @"(?:__nullable|nullable|__attribute__\\(\\(nullable\\)\\))"; - NSString *nonnullPattern = @"(?:__nonnull|nonnull|__attribute__\\(\\(nonnull\\)\\))"; - NSString *annotationPattern = [NSString stringWithFormat:@"(?:(?:(%@)|%@|(%@)|(%@))\\s*)", - unusedPattern, constPattern, nullablePattern, nonnullPattern]; - 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}; - NSMutableArray *args = [NSMutableArray array]; - [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"; - 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]]; - }]; - *arguments = [args copy]; - - // 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]; + NSString *selectorPart; + if (RCTParseIdentifier(input, &selectorPart)) { + [selector appendString:selectorPart]; } - - *objCMethodName = methodName; + RCTSkipWhitespace(input); + if (RCTReadChar(input, ':')) { + [selector appendString:@":"]; + RCTSkipWhitespace(input); + return YES; + } + return NO; } -- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName - JSMethodName:(NSString *)JSMethodName - moduleClass:(Class)moduleClass +static BOOL RCTParseUnused(const char **input) +{ + return RCTReadString(input, "__unused") || + RCTReadString(input, "__attribute__((unused))"); +} + +static RCTNullability RCTParseNullability(const char **input) +{ + if (RCTReadString(input, "nullable")) { + return RCTNullable; + } else if (RCTReadString(input, "nonnull")) { + return RCTNonnullable; + } + return RCTNullabilityUnspecified; +} + +SEL RCTParseMethodSignature(NSString *, NSArray **); +SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **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 + nullability:nullability + 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]; + return NSSelectorFromString(selector); +} + +- (instancetype)initWithMethodSignature:(NSString *)methodSignature + JSMethodName:(NSString *)JSMethodName + moduleClass:(Class)moduleClass { if ((self = [super init])) { _moduleClass = moduleClass; - _objCMethodName = [objCMethodName copy]; + _methodSignature = [methodSignature copy]; _JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({ - NSString *methodName = objCMethodName; + NSString *methodName = methodSignature; NSRange colonRange = [methodName rangeOfString:@":"]; if (colonRange.location != NSNotFound) { methodName = [methodName substringToIndex:colonRange.location]; } methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 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; }); - if ([_objCMethodName rangeOfString:@"RCTPromise"].length) { + if ([_methodSignature rangeOfString:@"RCTPromise"].length) { _functionType = RCTFunctionTypePromise; } else { _functionType = RCTFunctionTypeNormal; @@ -151,15 +181,12 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray *arguments; - NSString *objCMethodName = _objCMethodName; - RCTParseObjCMethodName(&objCMethodName, &arguments); - - _selector = NSSelectorFromString(objCMethodName); - RCTAssert(_selector, @"%@ is not a valid selector", objCMethodName); + _selector = RCTParseMethodSignature(_methodSignature, &arguments); + RCTAssert(_selector, @"%@ is not a valid selector", _methodSignature); // Create method invocation 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]; invocation.selector = _selector; _invocation = invocation; @@ -203,7 +230,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray + +typedef NS_ENUM(NSUInteger, RCTNullability) { + RCTNullabilityUnspecified, + RCTNullable, + RCTNonnullable, +}; diff --git a/React/Base/RCTParserUtils.h b/React/Base/RCTParserUtils.h new file mode 100644 index 0000000000..dcbe413ef7 --- /dev/null +++ b/React/Base/RCTParserUtils.h @@ -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 + +#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 diff --git a/React/Base/RCTParserUtils.m b/React/Base/RCTParserUtils.m new file mode 100644 index 0000000000..5e9182a5fa --- /dev/null +++ b/React/Base/RCTParserUtils.m @@ -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 diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index 273ef40c6b..344832b9aa 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -319,7 +319,7 @@ RCT_EXPORT_MODULE() #pragma mark - Exported JS Functions -RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys +RCT_EXPORT_METHOD(multiGet:(NSArray *)keys callback:(RCTResponseSenderBlock)callback) { NSDictionary *errorOut = [self _ensureSetup]; @@ -338,7 +338,7 @@ RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys callback(@[RCTNullIfNil(errors), result]); } -RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs +RCT_EXPORT_METHOD(multiSet:(NSArray *> *)kvPairs callback:(RCTResponseSenderBlock)callback) { NSDictionary *errorOut = [self _ensureSetup]; @@ -358,7 +358,7 @@ RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs callback(@[RCTNullIfNil(errors)]); } -RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs +RCT_EXPORT_METHOD(multiMerge:(NSArray *> *)kvPairs callback:(RCTResponseSenderBlock)callback) { NSDictionary *errorOut = [self _ensureSetup]; @@ -394,7 +394,7 @@ RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs callback(@[RCTNullIfNil(errors)]); } -RCT_EXPORT_METHOD(multiRemove:(NSStringArray *)keys +RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys callback:(RCTResponseSenderBlock)callback) { NSDictionary *errorOut = [self _ensureSetup]; diff --git a/React/Modules/RCTExceptionsManager.m b/React/Modules/RCTExceptionsManager.m index c536e20a10..791c163f16 100644 --- a/React/Modules/RCTExceptionsManager.m +++ b/React/Modules/RCTExceptionsManager.m @@ -34,7 +34,7 @@ RCT_EXPORT_MODULE() } RCT_EXPORT_METHOD(reportSoftException:(NSString *)message - stack:(NSDictionaryArray *)stack + stack:(NSArray *)stack exceptionId:(nonnull NSNumber *)exceptionId) { [_bridge.redBox showErrorMessage:message withStack:stack]; @@ -45,7 +45,7 @@ RCT_EXPORT_METHOD(reportSoftException:(NSString *)message } RCT_EXPORT_METHOD(reportFatalException:(NSString *)message - stack:(NSDictionaryArray *)stack + stack:(NSArray *)stack exceptionId:(nonnull NSNumber *)exceptionId) { [_bridge.redBox showErrorMessage:message withStack:stack]; @@ -66,7 +66,7 @@ RCT_EXPORT_METHOD(reportFatalException:(NSString *)message } RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message - stack:(NSDictionaryArray *)stack + stack:(NSArray *)stack exceptionId:(nonnull NSNumber *)exceptionId) { [_bridge.redBox updateErrorMessage:message withStack:stack]; @@ -78,7 +78,7 @@ RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message // Deprecated. Use reportFatalException directly instead. RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message - stack:(NSDictionaryArray *)stack) + stack:(NSArray *)stack) { [self reportFatalException:message stack:stack exceptionId:@-1]; } diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index c3c1ea5891..4812a548ef 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -721,11 +721,11 @@ RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag } RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag - moveFromIndices:(NSNumberArray *)moveFromIndices - moveToIndices:(NSNumberArray *)moveToIndices - addChildReactTags:(NSNumberArray *)addChildReactTags - addAtIndices:(NSNumberArray *)addAtIndices - removeAtIndices:(NSNumberArray *)removeAtIndices) + moveFromIndices:(NSArray *)moveFromIndices + moveToIndices:(NSArray *)moveToIndices + addChildReactTags:(NSArray *)addChildReactTags + addAtIndices:(NSArray *)addAtIndices + removeAtIndices:(NSArray *)removeAtIndices) { [self _manageChildren:containerReactTag moveFromIndices:moveFromIndices diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index d5ea0c76d5..3bc1cb5cf8 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; }; 13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; }; 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; }; + 13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */; }; 13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AB90C01B6FA36700713B4F /* RCTComponentData.m */; }; 13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.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 = ""; }; 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = ""; }; 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = ""; }; + 13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTParserUtils.h; sourceTree = ""; }; + 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTParserUtils.m; sourceTree = ""; }; + 13A6E20F1C19ABC700845B82 /* RCTNullability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNullability.h; sourceTree = ""; }; 13AB90BF1B6FA36700713B4F /* RCTComponentData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponentData.h; sourceTree = ""; }; 13AB90C01B6FA36700713B4F /* RCTComponentData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTComponentData.m; sourceTree = ""; }; 13AF1F851AE6E777005F5298 /* RCTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDefines.h; sourceTree = ""; }; @@ -518,6 +522,9 @@ 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */, 14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */, 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */, + 13A6E20F1C19ABC700845B82 /* RCTNullability.h */, + 13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */, + 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */, 142014181B32094000CC17BA /* RCTPerformanceLogger.h */, 142014171B32094000CC17BA /* RCTPerformanceLogger.m */, 830A229C1A66C68A008503DA /* RCTRootView.h */, @@ -674,6 +681,7 @@ 83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */, 83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */, 13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */, + 13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */, 13E067571A70F44B002CDEE1 /* RCTView.m in Sources */, 13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */, 13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */, diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m index 4a0b45ad1e..0f8287b728 100644 --- a/React/Views/RCTComponentData.m +++ b/React/Views/RCTComponentData.m @@ -114,7 +114,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) if ([managerClass respondsToSelector:selector]) { NSArray *typeAndKeyPath = ((NSArray *(*)(id, SEL))objc_msgSend)(managerClass, selector); - type = NSSelectorFromString([typeAndKeyPath[0] stringByAppendingString:@":"]); + type = RCTConvertSelectorForType(typeAndKeyPath[0]); keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil; } else { propBlock = ^(__unused id view, __unused id json) {}; diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m index 759a05b6d8..54d75f210c 100644 --- a/React/Views/RCTPickerManager.m +++ b/React/Views/RCTPickerManager.m @@ -10,7 +10,6 @@ #import "RCTPickerManager.h" #import "RCTBridge.h" -#import "RCTConvert.h" #import "RCTPicker.h" @implementation RCTPickerManager @@ -22,7 +21,7 @@ RCT_EXPORT_MODULE() return [RCTPicker new]; } -RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray) +RCT_EXPORT_VIEW_PROPERTY(items, NSArray) RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger) RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(color, UIColor) diff --git a/React/Views/RCTSegmentedControlManager.m b/React/Views/RCTSegmentedControlManager.m index e56be4cf03..c44f822cf3 100644 --- a/React/Views/RCTSegmentedControlManager.m +++ b/React/Views/RCTSegmentedControlManager.m @@ -22,7 +22,7 @@ RCT_EXPORT_MODULE() return [RCTSegmentedControl new]; } -RCT_EXPORT_VIEW_PROPERTY(values, NSStringArray) +RCT_EXPORT_VIEW_PROPERTY(values, NSArray) RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger) RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(momentary, BOOL)