Skip to content

Commit

Permalink
RCTUtils Obj-C nullability annotations
Browse files Browse the repository at this point in the history
Summary:
Add Objective-C nullability annotations to RCTUtils

public

Reviewed By: javache

Differential Revision: D2797331

fb-gh-sync-id: b918179625865760edc8c6fcc189ad78f819f3e3
  • Loading branch information
nicklockwood authored and facebook-github-bot-7 committed Jan 21, 2016
1 parent d33b554 commit 34d5fa2
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 55 deletions.
6 changes: 3 additions & 3 deletions React/Base/RCTAssert.m
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void _RCTAssertFormat(

void RCTFatal(NSError *error)
{
_RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@", [error localizedDescription]);
_RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@", error.localizedDescription);

RCTFatalHandler fatalHandler = RCTGetFatalHandler();
if (fatalHandler) {
Expand All @@ -128,8 +128,8 @@ void RCTFatal(NSError *error)
#if DEBUG
@try {
#endif
NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, [error localizedDescription]];
NSString *message = RCTFormatError([error localizedDescription], error.userInfo[RCTJSStackTraceKey], 75);
NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription];
NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 75);
[NSException raise:name format:@"%@", message];
#if DEBUG
} @catch (NSException *e) {}
Expand Down
48 changes: 26 additions & 22 deletions React/Base/RCTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
#import "RCTAssert.h"
#import "RCTDefines.h"

NS_ASSUME_NONNULL_BEGIN

// JSON serialization/deserialization
RCT_EXTERN NSString *RCTJSONStringify(id jsonObject, NSError **error);
RCT_EXTERN id RCTJSONParse(NSString *jsonString, NSError **error);
RCT_EXTERN id RCTJSONParseMutable(NSString *jsonString, NSError **error);
RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error);
RCT_EXTERN id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error);
RCT_EXTERN id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error);

// Strip non JSON-safe values from an object graph
RCT_EXTERN id RCTJSONClean(id object);
Expand Down Expand Up @@ -51,13 +53,13 @@ RCT_EXTERN void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement)
RCT_EXTERN BOOL RCTClassOverridesClassMethod(Class cls, SEL selector);
RCT_EXTERN BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector);

// Creates a standardized error object
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
// Creates a standardized error object to return in callbacks
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error);
RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error);
RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *__nullable error);

// The default error code that will be sent in the .code value of the Error object to js
// The default error code to use as the `code` property for callback error objects
RCT_EXTERN NSString *const RCTErrorUnspecified;

// Returns YES if React is running in a test environment
Expand All @@ -67,26 +69,26 @@ RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
RCT_EXTERN BOOL RCTRunningInAppExtension(void);

// Returns the shared UIApplication instance, or nil if running in an App Extension
RCT_EXTERN UIApplication *RCTSharedApplication(void);
RCT_EXTERN UIApplication *__nullable RCTSharedApplication(void);

// Returns the current main window, useful if you need to access the root view
// or view controller, e.g. to present a modal view controller or alert.
RCT_EXTERN UIWindow *RCTKeyWindow(void);
RCT_EXTERN UIWindow *__nullable RCTKeyWindow(void);

// Return a UIAlertView initialized with the given values
// or nil if running in an app extension
RCT_EXTERN UIAlertView *RCTAlertView(NSString *title,
NSString *message,
id delegate,
NSString *cancelButtonTitle,
NSArray<NSString *> *otherButtonTitles);
RCT_EXTERN UIAlertView *__nullable RCTAlertView(NSString *title,
NSString *__nullable message,
id __nullable delegate,
NSString *__nullable cancelButtonTitle,
NSArray<NSString *> *__nullable otherButtonTitles);

// Create an NSError in the RCTErrorDomain
RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);

// Convert nil values to NSNull, and vice-versa
RCT_EXTERN id RCTNilIfNull(id value);
RCT_EXTERN id RCTNullIfNil(id value);
RCT_EXTERN id __nullable RCTNilIfNull(id __nullable value);
RCT_EXTERN id RCTNullIfNil(id __nullable value);

// Convert NaN or infinite values to zero, as these aren't JSON-safe
RCT_EXTERN double RCTZeroIfNaN(double value);
Expand All @@ -95,14 +97,14 @@ RCT_EXTERN double RCTZeroIfNaN(double value);
RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);

// Gzip functionality - compression level in range 0 - 1 (-1 for default)
RCT_EXTERN NSData *RCTGzipData(NSData *data, float level);
RCT_EXTERN NSData *RCTGzipData(NSData *__nullable data, float level);

// Returns the relative path within the main bundle for an absolute URL
// (or nil, if the URL does not specify a path within the main bundle)
RCT_EXTERN NSString *RCTBundlePathForURL(NSURL *URL);
RCT_EXTERN NSString *__nullable RCTBundlePathForURL(NSURL *__nullable URL);

// Determines if a given image URL actually refers to an XCAsset
RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *imageURL);
RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL);

// Converts a CGColor to a hex string
RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
Expand All @@ -111,5 +113,7 @@ RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);

// URL manipulation
RCT_EXTERN NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param);
RCT_EXTERN NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value);
RCT_EXTERN NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param);
RCT_EXTERN NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value);

NS_ASSUME_NONNULL_END
67 changes: 37 additions & 30 deletions React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";

NSString *RCTJSONStringify(id jsonObject, NSError **error)
NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error)
{
static SEL JSONKitSelector = NULL;
static NSSet<Class> *collectionTypes;
Expand All @@ -44,14 +44,14 @@
}

// Use Foundation JSON method
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:jsonObject
options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
error:error];
NSData *jsonData = jsonObject ? [NSJSONSerialization
dataWithJSONObject:jsonObject
options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
error:error] : nil;
return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
}

static id _RCTJSONParse(NSString *jsonString, BOOL mutable, NSError **error)
static id __nullable _RCTJSONParse(NSString *__nullable jsonString, BOOL mutable, NSError **error)
{
static SEL JSONKitSelector = NULL;
static SEL JSONKitMutableSelector = NULL;
Expand Down Expand Up @@ -110,12 +110,12 @@ static id _RCTJSONParse(NSString *jsonString, BOOL mutable, NSError **error)
return nil;
}

id RCTJSONParse(NSString *jsonString, NSError **error)
id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error)
{
return _RCTJSONParse(jsonString, NO, error);
}

id RCTJSONParseMutable(NSString *jsonString, NSError **error)
id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error)
{
return _RCTJSONParse(jsonString, YES, error);
}
Expand Down Expand Up @@ -311,18 +311,22 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
return NO;
}

NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData)
NSDictionary<NSString *, id> *RCTMakeError(NSString *message,
id __nullable toStringify,
NSDictionary<NSString *, id> *__nullable extraData)
{
if (toStringify) {
message = [message stringByAppendingString:[toStringify description]];
}

NSMutableDictionary<NSString *, id> *error = [NSMutableDictionary dictionaryWithDictionary:extraData];
NSMutableDictionary<NSString *, id> *error = [extraData mutableCopy] ?: [NSMutableDictionary new];
error[@"message"] = message;
return error;
}

NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData)
NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message,
id __nullable toStringify,
NSDictionary<NSString *, id> *__nullable extraData)
{
NSDictionary<NSString *, id> *error = RCTMakeError(message, toStringify, extraData);
RCTLogError(@"\nError: %@", error);
Expand All @@ -331,11 +335,15 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)

NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error)
{
return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified, nil, error);
return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified,
error.localizedDescription,
error);
}

// TODO: Can we just replace RCTMakeError with this function instead?
NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error)
NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code,
NSString *message,
NSError *__nullable error)
{
NSString *errorMessage;
NSArray<NSString *> *stackTrace = [NSThread callStackSymbols];
Expand All @@ -356,7 +364,6 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
return RCTMakeError(errorMessage, nil, errorInfo);
}


BOOL RCTRunningInTestEnvironment(void)
{
static BOOL isTestEnvironment = NO;
Expand All @@ -372,15 +379,15 @@ BOOL RCTRunningInAppExtension(void)
return [[[[NSBundle mainBundle] bundlePath] pathExtension] isEqualToString:@"appex"];
}

UIApplication *RCTSharedApplication(void)
UIApplication *__nullable RCTSharedApplication(void)
{
if (RCTRunningInAppExtension()) {
return nil;
}
return [[UIApplication class] performSelector:@selector(sharedApplication)];
}

UIWindow *RCTKeyWindow(void)
UIWindow *__nullable RCTKeyWindow(void)
{
if (RCTRunningInAppExtension()) {
return nil;
Expand All @@ -390,11 +397,11 @@ BOOL RCTRunningInAppExtension(void)
return RCTSharedApplication().keyWindow;
}

UIAlertView *RCTAlertView(NSString *title,
NSString *message,
id delegate,
NSString *cancelButtonTitle,
NSArray<NSString *> *otherButtonTitles)
UIAlertView *__nullable RCTAlertView(NSString *title,
NSString *__nullable message,
id __nullable delegate,
NSString *__nullable cancelButtonTitle,
NSArray<NSString *> *__nullable otherButtonTitles)
{
if (RCTRunningInAppExtension()) {
RCTLogError(@"RCTAlertView is unavailable when running in an app extension");
Expand All @@ -421,12 +428,12 @@ BOOL RCTRunningInAppExtension(void)
return [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
}

id RCTNullIfNil(id value)
id RCTNullIfNil(id __nullable value)
{
return value ?: (id)kCFNull;
}

id RCTNilIfNull(id value)
id __nullable RCTNilIfNull(id __nullable value)
{
return value == (id)kCFNull ? nil : value;
}
Expand All @@ -443,14 +450,14 @@ RCT_EXTERN double RCTZeroIfNaN(double value)
[data base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]]];
}

BOOL RCTIsGzippedData(NSData *); // exposed for unit testing purposes
BOOL RCTIsGzippedData(NSData *data)
BOOL RCTIsGzippedData(NSData *__nullable); // exposed for unit testing purposes
BOOL RCTIsGzippedData(NSData *__nullable data)
{
UInt8 *bytes = (UInt8 *)data.bytes;
return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
}

NSData *RCTGzipData(NSData *input, float level)
NSData *RCTGzipData(NSData *__nullable input, float level)
{
if (input.length == 0 || RCTIsGzippedData(input)) {
return input;
Expand Down Expand Up @@ -493,7 +500,7 @@ BOOL RCTIsGzippedData(NSData *data)
return output;
}

NSString *RCTBundlePathForURL(NSURL *URL)
NSString *__nullable RCTBundlePathForURL(NSURL *__nullable URL)
{
if (!URL.fileURL) {
// Not a file path
Expand All @@ -512,7 +519,7 @@ BOOL RCTIsGzippedData(NSData *data)
return path;
}

BOOL RCTIsXCAssetURL(NSURL *imageURL)
BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL)
{
NSString *name = RCTBundlePathForURL(imageURL);
if (name.pathComponents.count != 1) {
Expand Down Expand Up @@ -598,7 +605,7 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
}

NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param)
NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param)
{
RCTAssertParam(param);
if (!URL) {
Expand All @@ -618,7 +625,7 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
return nil;
}

NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value)
NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value)
{
RCTAssertParam(param);
if (!URL) {
Expand Down

0 comments on commit 34d5fa2

Please sign in to comment.