diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 415a5968f..cf7f056e3 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -17,7 +17,6 @@ #import "RCTLog.h" #import "RCTPointerEvents.h" - /** * This class provides a collection of conversion functions for mapping * JSON objects to native types and classes. These are useful when writing @@ -39,10 +38,11 @@ + (NSUInteger)NSUInteger:(id)json; + (NSArray *)NSArray:(id)json; -+ (NSSet *)NSSet:(id)json; + (NSDictionary *)NSDictionary:(id)json; + (NSString *)NSString:(id)json; + (NSNumber *)NSNumber:(id)json; + ++ (NSSet *)NSSet:(id)json; + (NSData *)NSData:(id)json; + (NSIndexSet *)NSIndexSet:(id)json; @@ -94,6 +94,9 @@ typedef NSURL RCTFileURL; size:(id)size weight:(id)weight style:(id)style scaleMultiplier:(CGFloat)scaleMultiplier; +typedef NSArray NSArrayArray; ++ (NSArrayArray *)NSArrayArray:(id)json; + typedef NSArray NSStringArray; + (NSStringArray *)NSStringArray:(id)json; @@ -164,7 +167,6 @@ RCT_CUSTOM_CONVERTER(type, name, [json getter]) #define RCT_CUSTOM_CONVERTER(type, name, code) \ + (type)name:(id)json \ { \ - json = (json == (id)kCFNull) ? nil : json; \ if (!RCT_DEBUG) { \ return code; \ } else { \ @@ -185,7 +187,7 @@ RCT_CUSTOM_CONVERTER(type, name, [json getter]) * detailed error reporting if an invalid value is passed in. */ #define RCT_NUMBER_CONVERTER(type, getter) \ -RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter]) +RCT_CUSTOM_CONVERTER(type, type, [RCT_DEBUG ? [self NSNumber:json] : json getter]) /** * This macro is used for creating converters for enum types. diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index afa0bea46..b83089973 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -29,38 +29,33 @@ RCT_NUMBER_CONVERTER(uint64_t, unsignedLongLongValue); RCT_NUMBER_CONVERTER(NSInteger, integerValue) RCT_NUMBER_CONVERTER(NSUInteger, unsignedIntegerValue) -RCT_CUSTOM_CONVERTER(NSArray *, NSArray, [NSArray arrayWithArray:json]) +/** + * This macro is used for creating converter functions for directly + * representable json values that require no conversion. + */ +#if RCT_DEBUG +#define RCT_JSON_CONVERTER(type) \ ++ (type *)type:(id)json \ +{ \ + if ([json isKindOfClass:[type class]]) { \ + return json; \ + } else if (json) { \ + RCTLogConvertError(json, @#type); \ + } \ + return nil; \ +} +#else +#define RCT_JSON_CONVERTER(type) \ ++ (type *)type:(id)json { return json; } +#endif + +RCT_JSON_CONVERTER(NSArray) +RCT_JSON_CONVERTER(NSDictionary) +RCT_JSON_CONVERTER(NSString) +RCT_JSON_CONVERTER(NSNumber) + RCT_CUSTOM_CONVERTER(NSSet *, NSSet, [NSSet setWithArray:json]) -RCT_CUSTOM_CONVERTER(NSDictionary *, NSDictionary, [NSDictionary dictionaryWithDictionary:json]) -RCT_CONVERTER(NSString *, NSString, description) - -+ (NSNumber *)NSNumber:(id)json -{ - if ([json isKindOfClass:[NSNumber class]]) { - return json; - } else if ([json isKindOfClass:[NSString class]]) { - static NSNumberFormatter *formatter; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - formatter = [[NSNumberFormatter alloc] init]; - formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; - }); - NSNumber *number = [formatter numberFromString:json]; - if (!number) { - RCTLogConvertError(json, @"a number"); - } - return number; - } else if (json && json != (id)kCFNull) { - RCTLogConvertError(json, @"a number"); - } - return nil; -} - -+ (NSData *)NSData:(id)json -{ - // TODO: should we automatically decode base64 data? Probably not... - return [[self NSString:json] dataUsingEncoding:NSUTF8StringEncoding]; -} +RCT_CUSTOM_CONVERTER(NSData *, NSData, [json dataUsingEncoding:NSUTF8StringEncoding]) + (NSIndexSet *)NSIndexSet:(id)json { @@ -79,7 +74,7 @@ RCT_CONVERTER(NSString *, NSString, description) + (NSURL *)NSURL:(id)json { NSString *path = [self NSString:json]; - if (!path.length) { + if (!path) { return nil; } @@ -155,7 +150,7 @@ RCT_CONVERTER(NSString *, NSString, description) "Expected format: YYYY-MM-DD'T'HH:mm:ss.sssZ", json); } return date; - } else if (json && json != (id)kCFNull) { + } else if (json) { RCTLogConvertError(json, @"a date"); } return nil; @@ -169,7 +164,7 @@ RCT_CUSTOM_CONVERTER(NSTimeZone *, NSTimeZone, [NSTimeZone timeZoneForSecondsFro NSNumber *RCTConvertEnumValue(const char *typeName, NSDictionary *mapping, NSNumber *defaultValue, id json) { - if (!json || json == (id)kCFNull) { + if (!json) { return defaultValue; } if ([json isKindOfClass:[NSNumber class]]) { @@ -180,13 +175,12 @@ NSNumber *RCTConvertEnumValue(const char *typeName, NSDictionary *mapping, NSNum RCTLogError(@"Invalid %s '%@'. should be one of: %@", typeName, json, allValues); return defaultValue; } - - if (![json isKindOfClass:[NSString class]]) { + if (RCT_DEBUG && ![json isKindOfClass:[NSString class]]) { RCTLogError(@"Expected NSNumber or NSString for %s, received %@: %@", typeName, [json classForCoder], json); } id value = mapping[json]; - if (!value && [json description].length > 0) { + if (RCT_DEBUG && !value && [json description].length > 0) { RCTLogError(@"Invalid %s '%@'. should be one of: %@", typeName, json, [[mapping allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]); } return value ?: defaultValue; @@ -332,7 +326,7 @@ static void RCTConvertCGStructValue(const char *type, NSArray *fields, NSDiction for (NSUInteger i = 0; i < count; i++) { result[i] = [RCTConvert CGFloat:json[fields[i]]]; } - } else if (RCT_DEBUG && json && json != (id)kCFNull) { + } else if (json) { RCTLogConvertError(json, @(type)); } } @@ -619,8 +613,7 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[ blue:[self CGFloat:json[@"b"]] alpha:[self CGFloat:json[@"a"] ?: @1]]; - } - else if (RCT_DEBUG && json && json != (id)kCFNull) { + } else if (json) { RCTLogConvertError(json, @"a color"); } @@ -646,7 +639,7 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[ // TODO: we might as well cache the result of these checks (and possibly the // image itself) so as to reduce overhead on subsequent checks of the same input - if (!json || json == (id)kCFNull) { + if (!json) { return nil; } @@ -933,13 +926,25 @@ NSArray *RCTConvertArrayValue(SEL type, id json) return values; } -RCT_ARRAY_CONVERTER(NSString) -RCT_ARRAY_CONVERTER(NSDictionary) RCT_ARRAY_CONVERTER(NSURL) RCT_ARRAY_CONVERTER(RCTFileURL) -RCT_ARRAY_CONVERTER(NSNumber) RCT_ARRAY_CONVERTER(UIColor) +/** + * This macro is used for creating converter functions for directly + * representable json array values that require no conversion. + */ +#if RCT_DEBUG +#define RCT_JSON_ARRAY_CONVERTER(type) RCT_ARRAY_CONVERTER(type) +#else +#define RCT_JSON_ARRAY_CONVERTER(type) + (NSArray *)type##Array:(id)json { return json; } +#endif + +RCT_JSON_ARRAY_CONVERTER(NSArray) +RCT_JSON_ARRAY_CONVERTER(NSString) +RCT_JSON_ARRAY_CONVERTER(NSDictionary) +RCT_JSON_ARRAY_CONVERTER(NSNumber) + // Can't use RCT_ARRAY_CONVERTER due to bridged cast + (NSArray *)CGColorArray:(id)json {