From 8a57c4e9807cee5a4196cc50b40bc9e040c02398 Mon Sep 17 00:00:00 2001 From: Alex Akers Date: Wed, 8 Apr 2015 08:52:48 -0700 Subject: [PATCH] [React Native] RCT_EXPORT lvl.2 --- .../xcschemes/UIExplorer.xcscheme | 6 +- .../ActionSheetIOS/RCTActionSheetManager.m | 20 +- Libraries/AdSupport/RCTAdSupport.m | 12 +- .../RCTAnimationExperimentalManager.m | 17 +- Libraries/Geolocation/RCTLocationObserver.m | 16 +- Libraries/Image/RCTCameraRollManager.m | 14 +- Libraries/LinkingIOS/RCTLinkingManager.m | 18 +- Libraries/Network/RCTDataManager.m | 10 +- Libraries/Network/RCTReachability.m | 10 +- .../RCTPushNotificationManager.m | 17 +- Libraries/RCTTest/RCTTestModule.m | 8 +- Libraries/Vibration/RCTVibration.m | 3 +- React/Base/RCTBridge.m | 214 +++++++++++++----- React/Base/RCTBridgeModule.h | 41 +++- React/Base/RCTConvert.h | 28 ++- React/Base/RCTConvert.m | 2 - React/Modules/RCTAlertManager.m | 5 +- React/Modules/RCTAppState.m | 10 +- React/Modules/RCTAsyncLocalStorage.m | 23 +- React/Modules/RCTExceptionsManager.m | 10 +- React/Modules/RCTSourceCode.m | 4 +- React/Modules/RCTStatusBarManager.m | 10 +- React/Modules/RCTTiming.m | 31 +-- React/Modules/RCTUIManager.m | 133 ++++------- React/Views/RCTNavigatorManager.m | 8 +- React/Views/RCTScrollViewManager.m | 6 +- React/Views/RCTTabBarManager.m | 4 +- React/Views/RCTViewManager.m | 4 +- React/Views/RCTWebViewManager.m | 12 +- 29 files changed, 370 insertions(+), 326 deletions(-) diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme index 2189d2d0e..b231b77ee 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme @@ -72,7 +72,8 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" allowLocationSimulation = "YES"> - + - + +@interface RCTActionSheetManager () @end @@ -30,12 +30,10 @@ RCT_EXPORT_MODULE() return self; } -- (void)showActionSheetWithOptions:(NSDictionary *)options - failureCallback:(RCTResponseSenderBlock)failureCallback - successCallback:(RCTResponseSenderBlock)successCallback +RCT_EXPORT_METHOD(showActionSheetWithOptions:(NSDictionary *)options + failureCallback:(RCTResponseSenderBlock)failureCallback + successCallback:(RCTResponseSenderBlock)successCallback) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ UIActionSheet *actionSheet = [[UIActionSheet alloc] init]; @@ -65,12 +63,10 @@ RCT_EXPORT_MODULE() }); } -- (void)showShareActionSheetWithOptions:(NSDictionary *)options - failureCallback:(RCTResponseSenderBlock)failureCallback - successCallback:(RCTResponseSenderBlock)successCallback +RCT_EXPORT_METHOD(showShareActionSheetWithOptions:(NSDictionary *)options + failureCallback:(RCTResponseSenderBlock)failureCallback + successCallback:(RCTResponseSenderBlock)successCallback) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ NSMutableArray *items = [NSMutableArray array]; id message = options[@"message"]; @@ -137,7 +133,7 @@ RCT_EXPORT_MODULE() #pragma mark Private -static NSString *keyForInstance(id instance) +NS_INLINE NSString *keyForInstance(id instance) { return [NSString stringWithFormat:@"%p", instance]; } diff --git a/Libraries/AdSupport/RCTAdSupport.m b/Libraries/AdSupport/RCTAdSupport.m index 3dc1ba641..1b2ad92de 100644 --- a/Libraries/AdSupport/RCTAdSupport.m +++ b/Libraries/AdSupport/RCTAdSupport.m @@ -13,10 +13,9 @@ RCT_EXPORT_MODULE() -- (void)getAdvertisingId:(RCTResponseSenderBlock)callback withErrorCallback:(RCTResponseSenderBlock)errorCallback +RCT_EXPORT_METHOD(getAdvertisingId:(RCTResponseSenderBlock)callback + withErrorCallback:(RCTResponseSenderBlock)errorCallback) { - RCT_EXPORT(); - if ([ASIdentifierManager class]) { callback(@[[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]]); } else { @@ -24,12 +23,11 @@ RCT_EXPORT_MODULE() } } -- (void)getAdvertisingTrackingEnabled:(RCTResponseSenderBlock)callback withErrorCallback:(RCTResponseSenderBlock)errorCallback +RCT_EXPORT_METHOD(getAdvertisingTrackingEnabled:(RCTResponseSenderBlock)callback + withErrorCallback:(RCTResponseSenderBlock)errorCallback) { - RCT_EXPORT(); - if ([ASIdentifierManager class]) { - bool hasTracking = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; + BOOL hasTracking = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; callback(@[@(hasTracking)]); } else { return errorCallback(@[@"as_identifier_unavailable"]); diff --git a/Libraries/Animation/RCTAnimationExperimentalManager.m b/Libraries/Animation/RCTAnimationExperimentalManager.m index 8cc180112..0ce871344 100644 --- a/Libraries/Animation/RCTAnimationExperimentalManager.m +++ b/Libraries/Animation/RCTAnimationExperimentalManager.m @@ -63,10 +63,13 @@ RCT_EXPORT_MODULE() }; } -- (void)startAnimationForTag:(NSNumber *)reactTag animationTag:(NSNumber *)animationTag duration:(double)duration delay:(double)delay easingSample:(NSArray *)easingSample properties:(NSDictionary *)properties +RCT_EXPORT_METHOD(startAnimationForTag:(NSNumber *)reactTag + animationTag:(NSNumber *)animationTag + duration:(NSTimeInterval)duration + delay:(NSTimeInterval)delay + easingSample:(NSArray *)easingSample + properties:(NSDictionary *)properties) { - RCT_EXPORT(startAnimation); - __weak RCTAnimationExperimentalManager *weakSelf = self; [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTAnimationExperimentalManager *strongSelf = weakSelf; @@ -165,8 +168,8 @@ RCT_EXPORT_MODULE() } CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:key]; - animation.beginTime = CACurrentMediaTime() + delay / 1000.0; - animation.duration = duration / 1000.0; + animation.beginTime = CACurrentMediaTime() + delay; + animation.duration = duration; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; animation.values = sampledValues; @@ -180,10 +183,8 @@ RCT_EXPORT_MODULE() }]; } -- (void)stopAnimation:(NSNumber *)animationTag +RCT_EXPORT_METHOD(stopAnimation:(NSNumber *)animationTag) { - RCT_EXPORT(stopAnimation); - __weak RCTAnimationExperimentalManager *weakSelf = self; [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTAnimationExperimentalManager *strongSelf = weakSelf; diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m index bdad54189..05541f323 100644 --- a/Libraries/Geolocation/RCTLocationObserver.m +++ b/Libraries/Geolocation/RCTLocationObserver.m @@ -153,10 +153,8 @@ RCT_EXPORT_MODULE() #pragma mark - Public API -- (void)startObserving:(NSDictionary *)optionsJSON +RCT_EXPORT_METHOD(startObserving:(NSDictionary *)optionsJSON) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ // Select best options @@ -172,10 +170,8 @@ RCT_EXPORT_MODULE() }); } -- (void)stopObserving +RCT_EXPORT_METHOD(stopObserving) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ // Stop observing @@ -189,12 +185,10 @@ RCT_EXPORT_MODULE() }); } -- (void)getCurrentPosition:(NSDictionary *)optionsJSON - withSuccessCallback:(RCTResponseSenderBlock)successBlock - errorCallback:(RCTResponseSenderBlock)errorBlock +RCT_EXPORT_METHOD(getCurrentPosition:(NSDictionary *)optionsJSON + withSuccessCallback:(RCTResponseSenderBlock)successBlock + errorCallback:(RCTResponseSenderBlock)errorBlock) { - RCT_EXPORT(); - if (!successBlock) { RCTLogError(@"%@.getCurrentPosition called with nil success parameter.", [self class]); return; diff --git a/Libraries/Image/RCTCameraRollManager.m b/Libraries/Image/RCTCameraRollManager.m index 92254c26b..8e6c8a532 100644 --- a/Libraries/Image/RCTCameraRollManager.m +++ b/Libraries/Image/RCTCameraRollManager.m @@ -14,17 +14,17 @@ #import #import - #import "RCTImageLoader.h" +#import "RCTImageLoader.h" #import "RCTLog.h" @implementation RCTCameraRollManager RCT_EXPORT_MODULE() -- (void)saveImageWithTag:(NSString *)imageTag successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback +RCT_EXPORT_METHOD(saveImageWithTag:(NSString *)imageTag + successCallback:(RCTResponseSenderBlock)successCallback + errorCallback:(RCTResponseSenderBlock)errorCallback) { - RCT_EXPORT(); - [RCTImageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) { if (loadError) { errorCallback(@[[loadError localizedDescription]]); @@ -61,10 +61,10 @@ RCT_EXPORT_MODULE() }]); } -- (void)getPhotos:(NSDictionary *)params callback:(RCTResponseSenderBlock)callback errorCallback:(RCTResponseSenderBlock)errorCallback +RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params + callback:(RCTResponseSenderBlock)callback + errorCallback:(RCTResponseSenderBlock)errorCallback) { - RCT_EXPORT(); - NSUInteger first = [params[@"first"] integerValue]; NSString *afterCursor = params[@"after"]; NSString *groupTypesStr = params[@"groupTypes"]; diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m index fcde00055..33fac75f0 100644 --- a/Libraries/LinkingIOS/RCTLinkingManager.m +++ b/Libraries/LinkingIOS/RCTLinkingManager.m @@ -16,10 +16,10 @@ NSString *const RCTOpenURLNotification = @"RCTOpenURLNotification"; @implementation RCTLinkingManager -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + - (instancetype)init { if ((self = [super init])) { @@ -54,19 +54,15 @@ RCT_EXPORT_MODULE() body:[notification userInfo]]; } -- (void)openURL:(NSString *)url +RCT_EXPORT_METHOD(openURL:(NSURL *)url) { - RCT_EXPORT(); - - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; + [[UIApplication sharedApplication] openURL:url]; } -- (void)canOpenURL:(NSString *)url - callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(canOpenURL:(NSURL *)url + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - - BOOL supported = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:url]]; + BOOL supported = [[UIApplication sharedApplication] canOpenURL:url]; callback(@[@(supported)]); } diff --git a/Libraries/Network/RCTDataManager.m b/Libraries/Network/RCTDataManager.m index f678f17cd..6aa2842a3 100644 --- a/Libraries/Network/RCTDataManager.m +++ b/Libraries/Network/RCTDataManager.m @@ -21,13 +21,11 @@ RCT_EXPORT_MODULE() * Executes a network request. * The responseSender block won't be called on same thread as called. */ -- (void)executeQuery:(NSString *)queryType - query:(id)query - queryHash:(__unused NSString *)queryHash - responseSender:(RCTResponseSenderBlock)responseSender +RCT_EXPORT_METHOD(queryData:(NSString *)queryType + withQuery:(id)query + queryHash:(__unused NSString *)queryHash + responseSender:(RCTResponseSenderBlock)responseSender) { - RCT_EXPORT(queryData); - if ([queryType isEqualToString:@"http"]) { // Parse query diff --git a/Libraries/Network/RCTReachability.m b/Libraries/Network/RCTReachability.m index d234addfb..b5f30de30 100644 --- a/Libraries/Network/RCTReachability.m +++ b/Libraries/Network/RCTReachability.m @@ -23,8 +23,6 @@ static NSString *const RCTReachabilityStateCell = @"cell"; NSString *_status; } -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) @@ -55,6 +53,8 @@ static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SC } } +RCT_EXPORT_MODULE() + #pragma mark - Lifecycle - (instancetype)initWithHost:(NSString *)host @@ -83,11 +83,9 @@ static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SC #pragma mark - Public API // TODO: remove error callback - not needed except by Subscribable interface -- (void)getCurrentReachability:(RCTResponseSenderBlock)getSuccess - withErrorCallback:(__unused RCTResponseSenderBlock)getError +RCT_EXPORT_METHOD(getCurrentReachability:(RCTResponseSenderBlock)getSuccess + withErrorCallback:(__unused RCTResponseSenderBlock)getError) { - RCT_EXPORT(); - getSuccess(@[@{@"network_reachability": _status}]); } diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m index 14dd97c82..17ceb204c 100644 --- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m +++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m @@ -68,29 +68,23 @@ RCT_EXPORT_MODULE() /** * Update the application icon badge number on the home screen */ -+ (void)setApplicationIconBadgeNumber:(NSInteger)number +RCT_EXPORT_METHOD(setApplicationIconBadgeNumber:(NSInteger)number) { - RCT_EXPORT(); - [UIApplication sharedApplication].applicationIconBadgeNumber = number; } /** * Get the current application icon badge number on the home screen */ -+ (void)getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - callback(@[ @([UIApplication sharedApplication].applicationIconBadgeNumber) ]); } -+ (void)requestPermissions +RCT_EXPORT_METHOD(requestPermissions) { - RCT_EXPORT(); - #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 // if we are targeting iOS 7, *and* the new UIUserNotificationSettings @@ -106,13 +100,10 @@ RCT_EXPORT_MODULE() UIUserNotificationType types = UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert; UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings]; - } -+ (void)checkPermissions:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - NSMutableDictionary *permissions = [[NSMutableDictionary alloc] init]; UIUserNotificationType types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types]; diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m index eccd27f3d..58b6572f8 100644 --- a/Libraries/RCTTest/RCTTestModule.m +++ b/Libraries/RCTTest/RCTTestModule.m @@ -32,10 +32,8 @@ RCT_EXPORT_MODULE() return self; } -- (void)verifySnapshot:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - if (!_snapshotController) { RCTLogWarn(@"No snapshot controller configured."); callback(@[]); @@ -55,10 +53,8 @@ RCT_EXPORT_MODULE() }); } -- (void)markTestCompleted +RCT_EXPORT_METHOD(markTestCompleted) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ _done = YES; }); diff --git a/Libraries/Vibration/RCTVibration.m b/Libraries/Vibration/RCTVibration.m index a59990d12..f2544d767 100644 --- a/Libraries/Vibration/RCTVibration.m +++ b/Libraries/Vibration/RCTVibration.m @@ -15,9 +15,8 @@ RCT_EXPORT_MODULE() -- (void)vibrate +RCT_EXPORT_METHOD(vibrate) { - RCT_EXPORT(); AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 837950cef..c48afa565 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -213,11 +213,18 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void) static Class _globalExecutorClass; +NS_INLINE NSString *RCTStringUpToFirstArgument(NSString *methodName) { + NSRange colonRange = [methodName rangeOfString:@":"]; + if (colonRange.length) { + methodName = [methodName substringToIndex:colonRange.location]; + } + return methodName; +} + - (instancetype)initWithMethodName:(NSString *)methodName JSMethodName:(NSString *)JSMethodName { if ((self = [super init])) { - _methodName = methodName; NSArray *parts = [[methodName substringWithRange:(NSRange){2, methodName.length - 3}] componentsSeparatedByString:@" "]; @@ -228,14 +235,39 @@ static Class _globalExecutorClass; _moduleClassName = [_moduleClassName substringToIndex:categoryRange.location]; } + NSArray *argumentNames = nil; + if ([parts[1] hasPrefix:@"__rct_export__"]) { + // New format + NSString *selectorString = [parts[1] substringFromIndex:14]; + _selector = NSSelectorFromString(selectorString); + _JSMethodName = RCTStringUpToFirstArgument(selectorString); + + static NSRegularExpression *regExp; + if (!regExp) { + NSString *unusedPattern = @"(?:(?:__unused|__attribute__\\(\\(unused\\)\\)))"; + NSString *constPattern = @"(?:const)"; + NSString *constUnusedPattern = [NSString stringWithFormat:@"(?:(?:%@|%@)\\s*)", unusedPattern, constPattern]; + NSString *pattern = [NSString stringWithFormat:@"\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\)", constUnusedPattern]; + regExp = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL]; + } + + argumentNames = [NSMutableArray array]; + [regExp enumerateMatchesInString:JSMethodName options:0 range:NSMakeRange(0, JSMethodName.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + NSString *argumentName = [JSMethodName substringWithRange:[result rangeAtIndex:1]]; + [(NSMutableArray *)argumentNames addObject:argumentName]; + }]; + } else { + // Old format + NSString *selectorString = parts[1]; + _selector = NSSelectorFromString(selectorString); + _JSMethodName = JSMethodName ?: RCTStringUpToFirstArgument(selectorString); + } + // Extract class and method details _isClassMethod = [methodName characterAtIndex:0] == '+'; _moduleClass = NSClassFromString(_moduleClassName); - _selector = NSSelectorFromString(parts[1]); - _JSMethodName = JSMethodName ?: [NSStringFromSelector(_selector) componentsSeparatedByString:@":"][0]; #if DEBUG - // Sanity check RCTAssert([_moduleClass conformsToProtocol:@protocol(RCTBridgeModule)], @"You are attempting to export the method %@, but %@ does not \ @@ -250,15 +282,87 @@ static Class _globalExecutorClass; // Process arguments NSUInteger numberOfArguments = _methodSignature.numberOfArguments; NSMutableArray *argumentBlocks = [[NSMutableArray alloc] initWithCapacity:numberOfArguments - 2]; - for (NSUInteger i = 2; i < numberOfArguments; i++) { - const char *argumentType = [_methodSignature getArgumentTypeAtIndex:i]; - switch (argumentType[0]) { #define RCT_ARG_BLOCK(_logic) \ - [argumentBlocks addObject:^(RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \ - _logic \ - [invocation setArgument:&value atIndex:index]; \ - }]; \ + [argumentBlocks addObject:^(RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \ + _logic \ + [invocation setArgument:&value atIndex:index]; \ + }]; \ + + void (^addBlockArgument)(void) = ^{ + RCT_ARG_BLOCK( + if (json && ![json isKindOfClass:[NSNumber class]]) { + RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index, + json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName); + return; + } + + // Marked as autoreleasing, because NSInvocation doesn't retain arguments + __autoreleasing id value = (json ? ^(NSArray *args) { + [bridge _invokeAndProcessModule:@"BatchedBridge" + method:@"invokeCallbackAndReturnFlushedQueue" + arguments:@[json, args]]; + } : ^(NSArray *unused) {}); + ) + }; + + void (^defaultCase)(const char *) = ^(const char *argumentType) { + static const char *blockType = @encode(typeof(^{})); + if (!strcmp(argumentType, blockType)) { + addBlockArgument(); + } else { + RCT_ARG_BLOCK( id value = json; ) + } + }; + + for (NSUInteger i = 2; i < numberOfArguments; i++) { + const char *argumentType = [_methodSignature getArgumentTypeAtIndex:i]; + + BOOL useFallback = YES; + if (argumentNames) { + NSString *argumentName = argumentNames[i - 2]; + SEL selector = NSSelectorFromString([argumentName stringByAppendingString:@":"]); + if ([RCTConvert respondsToSelector:selector]) { + useFallback = NO; + switch (argumentType[0]) { + +#define RCT_CONVERT_CASE(_value, _type) \ + case _value: { \ + _type (*convert)(id, SEL, id) = (typeof(convert))[RCTConvert methodForSelector:selector]; \ + RCT_ARG_BLOCK( _type value = convert([RCTConvert class], selector, json); ) \ + break; \ + } + + RCT_CONVERT_CASE(':', SEL) + RCT_CONVERT_CASE('*', const char *) + RCT_CONVERT_CASE('c', char) + RCT_CONVERT_CASE('C', unsigned char) + RCT_CONVERT_CASE('s', short) + RCT_CONVERT_CASE('S', unsigned short) + RCT_CONVERT_CASE('i', int) + RCT_CONVERT_CASE('I', unsigned int) + RCT_CONVERT_CASE('l', long) + RCT_CONVERT_CASE('L', unsigned long) + RCT_CONVERT_CASE('q', long long) + RCT_CONVERT_CASE('Q', unsigned long long) + RCT_CONVERT_CASE('f', float) + RCT_CONVERT_CASE('d', double) + RCT_CONVERT_CASE('B', BOOL) + RCT_CONVERT_CASE('@', id) + RCT_CONVERT_CASE('^', void *) + + default: + defaultCase(argumentType); + break; + } + } else if ([argumentName isEqualToString:@"RCTResponseSenderBlock"]) { + addBlockArgument(); + useFallback = NO; + } + } + + if (useFallback) { + switch (argumentType[0]) { #define RCT_CASE(_value, _class, _logic) \ case _value: { \ @@ -273,61 +377,46 @@ static Class _globalExecutorClass; break; \ } - RCT_CASE(':', NSString, SEL value = NSSelectorFromString(json); ); - RCT_CASE('*', NSString, const char *value = [json UTF8String]; ); + RCT_CASE(':', NSString, SEL value = NSSelectorFromString(json); ) + RCT_CASE('*', NSString, const char *value = [json UTF8String]; ) #define RCT_SIMPLE_CASE(_value, _type, _selector) \ - case _value: { \ - RCT_ARG_BLOCK( \ - if (json && ![json respondsToSelector:@selector(_selector)]) { \ - RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \ - index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \ - return; \ - } \ - _type value = [json _selector]; \ - ) \ - break; \ - } - - RCT_SIMPLE_CASE('c', char, charValue) - RCT_SIMPLE_CASE('C', unsigned char, unsignedCharValue) - RCT_SIMPLE_CASE('s', short, shortValue) - RCT_SIMPLE_CASE('S', unsigned short, unsignedShortValue) - RCT_SIMPLE_CASE('i', int, intValue) - RCT_SIMPLE_CASE('I', unsigned int, unsignedIntValue) - RCT_SIMPLE_CASE('l', long, longValue) - RCT_SIMPLE_CASE('L', unsigned long, unsignedLongValue) - RCT_SIMPLE_CASE('q', long long, longLongValue) - RCT_SIMPLE_CASE('Q', unsigned long long, unsignedLongLongValue) - RCT_SIMPLE_CASE('f', float, floatValue) - RCT_SIMPLE_CASE('d', double, doubleValue) - RCT_SIMPLE_CASE('B', BOOL, boolValue) - - default: { - static const char *blockType = @encode(typeof(^{})); - if (!strcmp(argumentType, blockType)) { - RCT_ARG_BLOCK( - if (json && ![json isKindOfClass:[NSNumber class]]) { - RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index, - json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName); - return; - } - // Marked as autoreleasing, because NSInvocation doesn't retain arguments - __autoreleasing id value = (json ? ^(NSArray *args) { - [bridge _invokeAndProcessModule:@"BatchedBridge" - method:@"invokeCallbackAndReturnFlushedQueue" - arguments:@[json, args]]; - } : ^(NSArray *unused) {}); - ) - } else { - RCT_ARG_BLOCK( id value = json; ) + case _value: { \ + RCT_ARG_BLOCK( \ + if (json && ![json respondsToSelector:@selector(_selector)]) { \ + RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \ + index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \ + return; \ + } \ + _type value = [json _selector]; \ + ) \ + break; \ } - break; + + RCT_SIMPLE_CASE('c', char, charValue) + RCT_SIMPLE_CASE('C', unsigned char, unsignedCharValue) + RCT_SIMPLE_CASE('s', short, shortValue) + RCT_SIMPLE_CASE('S', unsigned short, unsignedShortValue) + RCT_SIMPLE_CASE('i', int, intValue) + RCT_SIMPLE_CASE('I', unsigned int, unsignedIntValue) + RCT_SIMPLE_CASE('l', long, longValue) + RCT_SIMPLE_CASE('L', unsigned long, unsignedLongValue) + RCT_SIMPLE_CASE('q', long long, longLongValue) + RCT_SIMPLE_CASE('Q', unsigned long long, unsignedLongLongValue) + RCT_SIMPLE_CASE('f', float, floatValue) + RCT_SIMPLE_CASE('d', double, doubleValue) + RCT_SIMPLE_CASE('B', BOOL, boolValue) + + default: + defaultCase(argumentType); + break; } } } + _argumentBlocks = [argumentBlocks copy]; } + return self; } @@ -337,7 +426,6 @@ static Class _globalExecutorClass; { #if DEBUG - // Sanity check RCTAssert([module class] == _moduleClass, @"Attempted to invoke method \ %@ on a module of class %@", _methodName, [module class]); @@ -354,6 +442,7 @@ static Class _globalExecutorClass; // Create invocation (we can't re-use this as it wouldn't be thread-safe) NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:_methodSignature]; [invocation setArgument:&_selector atIndex:1]; + [invocation retainArguments]; // Set arguments NSUInteger index = 0; @@ -361,7 +450,7 @@ static Class _globalExecutorClass; id arg = (json == [NSNull null]) ? nil : json; void (^block)(RCTBridge *, NSInvocation *, NSUInteger, id) = _argumentBlocks[index]; block(bridge, invocation, index + 2, arg); - index ++; + index++; } // Invoke method @@ -768,6 +857,11 @@ static id _latestJSExecutor; [_javaScriptExecutor invalidate]; _javaScriptExecutor = nil; + // Wait for queued methods to finish + dispatch_sync(self.shadowQueue, ^{ + // Make sure all dispatchers have been executed before continuing + }); + // Invalidate modules for (id target in _modulesByID.allObjects) { if ([target respondsToSelector:@selector(invalidate)]) { diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h index ddc6785ed..7fc526e35 100644 --- a/React/Base/RCTBridgeModule.h +++ b/React/Base/RCTBridgeModule.h @@ -48,8 +48,37 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response); * If omitted, the JS method name will match the first part of the Objective-C * method selector name (up to the first colon). */ -#define RCT_EXPORT(js_name) __attribute__((used, section("__DATA,RCTExport" \ -))) static const char *__rct_export_entry__[] = { __func__, #js_name } +#define RCT_EXPORT(js_name) \ + _Pragma("message(\"RCT_EXPORT is deprecated. Use RCT_EXPORT_METHOD instead.\")") \ + __attribute__((used, section("__DATA,RCTExport"))) \ + static const char *__rct_export_entry__[] = { __func__, #js_name } + +/** + * Wrap the parameter line of your method implementation with this macro to + * expose it to JS. Unlike the deprecated RCT_EXPORT, this macro does not take + * a js_name argument and the exposed method will match the first part of the + * Objective-C method selector name (up to the first colon). + * + * For example, in MyClass.m: + * + * - (void)doSomething:(NSString *)aString withA:(NSInteger)a andB:(NSInteger)b + * {} + * + * becomes + * + * RCT_EXPORT_METHOD(doSomething:(NSString *)aString + * withA:(NSInteger)a + * andB:(NSInteger)b) + * {} + * + * and is exposed to JavaScript as `NativeModules.ModuleName.doSomething`. + */ +#define RCT_EXPORT_METHOD(method) \ + - (void)__rct_export__##method { \ + __attribute__((used, section("__DATA,RCTExport"))) \ + static const char *__rct_export_entry__[] = { __func__, #method }; \ + } \ + - (void)method /** * Injects constants into JS. These constants are made accessible via @@ -67,3 +96,11 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response); - (void)batchDidComplete; @end + +#ifdef __cplusplus +extern "C" { +#endif +void RCTBridgeModuleRegisterClass(Class cls, NSString *moduleName); +#ifdef __cplusplus +} +#endif diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 7e573370e..ff5fb970b 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -82,14 +82,26 @@ + (UIFont *)UIFont:(UIFont *)font withFamily:(id)family size:(id)size weight:(id)weight style:(id)style; -+ (NSArray *)NSStringArray:(id)json; -+ (NSArray *)NSDictionaryArray:(id)json; -+ (NSArray *)NSURLArray:(id)json; -+ (NSArray *)NSNumberArray:(id)json; -+ (NSArray *)UIColorArray:(id)json; -+ (NSArray *)CGColorArray:(id)json; +typedef NSArray NSStringArray; ++ (NSStringArray *)NSStringArray:(id)json; -+ (BOOL)css_overflow:(id)json; +typedef NSArray NSDictionaryArray; ++ (NSDictionaryArray *)NSDictionaryArray:(id)json; + +typedef NSArray NSURLArray; ++ (NSURLArray *)NSURLArray:(id)json; + +typedef NSArray NSNumberArray; ++ (NSNumberArray *)NSNumberArray:(id)json; + +typedef NSArray UIColorArray; ++ (UIColorArray *)UIColorArray:(id)json; + +typedef NSArray CGColorArray; ++ (CGColorArray *)CGColorArray:(id)json; + +typedef BOOL css_overflow; ++ (css_overflow)css_overflow:(id)json; + (css_flex_direction_t)css_flex_direction_t:(id)json; + (css_justify_t)css_justify_t:(id)json; + (css_align_t)css_align_t:(id)json; @@ -195,7 +207,7 @@ RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter]) * This macro is used for creating converter functions for typed arrays. */ #define RCT_ARRAY_CONVERTER(type) \ -+ (NSArray *)type##Array:(id)json \ ++ (type##Array *)type##Array:(id)json \ { \ NSMutableArray *values = [[NSMutableArray alloc] init]; \ for (id jsonValue in [self NSArray:json]) { \ diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 1ddc9884c..fe9a9456b 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -742,8 +742,6 @@ RCT_ARRAY_CONVERTER(UIColor) return colors; } -typedef BOOL css_overflow; - RCT_ENUM_CONVERTER(css_overflow, (@{ @"hidden": @NO, @"visible": @YES diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m index 5ffb9c396..ae11ce52b 100644 --- a/React/Modules/RCTAlertManager.m +++ b/React/Modules/RCTAlertManager.m @@ -49,10 +49,9 @@ RCT_EXPORT_MODULE() * Buttons are displayed in the order they are specified. If "cancel" is used as * the button key, it will be differently highlighted, according to iOS UI conventions. */ -- (void)alertWithArgs:(NSDictionary *)args callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - NSString *title = args[@"title"]; NSString *message = args[@"message"]; NSArray *buttons = args[@"buttons"]; diff --git a/React/Modules/RCTAppState.m b/React/Modules/RCTAppState.m index 148bbfc3c..9743e5042 100644 --- a/React/Modules/RCTAppState.m +++ b/React/Modules/RCTAppState.m @@ -33,10 +33,10 @@ static NSString *RCTCurrentAppBackgroundState() NSString *_lastKnownState; } -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + #pragma mark - Lifecycle - (instancetype)init @@ -81,11 +81,9 @@ RCT_EXPORT_MODULE() /** * Get the current background/foreground state of the app */ -- (void)getCurrentAppState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error +RCT_EXPORT_METHOD(getCurrentAppState:(RCTResponseSenderBlock)callback + error:(__unused RCTResponseSenderBlock)error) { - RCT_EXPORT(); - callback(@[@{@"app_state": _lastKnownState}]); } diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index feec17048..8e6d414cf 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -188,10 +188,9 @@ RCT_EXPORT_MODULE() #pragma mark - Exported JS Functions -- (void)multiGet:(NSArray *)keys callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(multiGet:(NSArray *)keys + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - if (!callback) { RCTLogError(@"Called getItem without a callback."); return; @@ -214,10 +213,9 @@ RCT_EXPORT_MODULE() }); } -- (void)multiSet:(NSArray *)kvPairs callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(multiSet:(NSArray *)kvPairs + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - dispatch_async(RCTFileQueue(), ^{ id errorOut = [self _ensureSetup]; if (errorOut) { @@ -236,10 +234,9 @@ RCT_EXPORT_MODULE() }); } -- (void)multiRemove:(NSArray *)keys callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - dispatch_async(RCTFileQueue(), ^{ id errorOut = [self _ensureSetup]; if (errorOut) { @@ -263,10 +260,8 @@ RCT_EXPORT_MODULE() }); } -- (void)clear:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(clear:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - dispatch_async(RCTFileQueue(), ^{ id errorOut = [self _ensureSetup]; if (!errorOut) { @@ -284,10 +279,8 @@ RCT_EXPORT_MODULE() }); } -- (void)getAllKeys:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(getAllKeys:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - dispatch_async(RCTFileQueue(), ^{ id errorOut = [self _ensureSetup]; if (errorOut) { diff --git a/React/Modules/RCTExceptionsManager.m b/React/Modules/RCTExceptionsManager.m index 97806011f..d6ce424d5 100644 --- a/React/Modules/RCTExceptionsManager.m +++ b/React/Modules/RCTExceptionsManager.m @@ -31,10 +31,9 @@ RCT_EXPORT_MODULE() return [self initWithDelegate:nil]; } -- (void)reportUnhandledExceptionWithMessage:(NSString *)message stack:(NSArray *)stack +RCT_EXPORT_METHOD(reportUnhandledExceptionWithMessage:(NSString *)message + stack:(NSArray *)stack) { - RCT_EXPORT(reportUnhandledException); - if (_delegate) { [_delegate unhandledJSExceptionWithMessage:message stack:stack]; } else { @@ -42,10 +41,9 @@ RCT_EXPORT_MODULE() } } -- (void)updateExceptionMessage:(NSString *)message stack:(NSArray *)stack +RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message + stack:(NSArray *)stack) { - RCT_EXPORT(updateExceptionMessage); - [[RCTRedBox sharedInstance] updateErrorMessage:message withStack:stack]; } diff --git a/React/Modules/RCTSourceCode.m b/React/Modules/RCTSourceCode.m index 1afffc3db..76e9190bc 100644 --- a/React/Modules/RCTSourceCode.m +++ b/React/Modules/RCTSourceCode.m @@ -16,9 +16,9 @@ RCT_EXPORT_MODULE() -- (void)getScriptText:(RCTResponseSenderBlock)successCallback failureCallback:(RCTResponseSenderBlock)failureCallback +RCT_EXPORT_METHOD(getScriptText:(RCTResponseSenderBlock)successCallback + failureCallback:(RCTResponseSenderBlock)failureCallback) { - RCT_EXPORT(); if (self.scriptText && self.scriptURL) { successCallback(@[@{@"text": self.scriptText, @"url":[self.scriptURL absoluteString]}]); } else { diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m index 2cc2bc40a..ad8ee1df6 100644 --- a/React/Modules/RCTStatusBarManager.m +++ b/React/Modules/RCTStatusBarManager.m @@ -26,10 +26,9 @@ static BOOL RCTViewControllerBasedStatusBarAppearance() RCT_EXPORT_MODULE() -- (void)setStyle:(UIStatusBarStyle)statusBarStyle animated:(BOOL)animated +RCT_EXPORT_METHOD(setStyle:(UIStatusBarStyle)statusBarStyle + animated:(BOOL)animated) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ if (RCTViewControllerBasedStatusBarAppearance()) { @@ -42,10 +41,9 @@ RCT_EXPORT_MODULE() }); } -- (void)setHidden:(BOOL)hidden withAnimation:(UIStatusBarAnimation)animation +RCT_EXPORT_METHOD(setHidden:(BOOL)hidden + withAnimation:(UIStatusBarAnimation)animation) { - RCT_EXPORT(); - dispatch_async(dispatch_get_main_queue(), ^{ if (RCTViewControllerBasedStatusBarAppearance()) { diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index 734046047..8c7ef1f23 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -61,10 +61,10 @@ id _updateTimer; } -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + RCT_IMPORT_METHOD(RCTJSTimers, callTimers) - (instancetype)init @@ -165,34 +165,29 @@ RCT_IMPORT_METHOD(RCTJSTimers, callTimers) * calculating the timer's target time. We calculate this by passing in * Date.now() from JS and then subtracting that from the current time here. */ -- (void)createTimer:(NSNumber *)callbackID - duration:(double)jsDuration - jsSchedulingTime:(double)jsSchedulingTime - repeats:(BOOL)repeats +RCT_EXPORT_METHOD(createTimer:(NSNumber *)callbackID + duration:(NSTimeInterval)jsDuration + jsSchedulingTime:(NSDate *)jsSchedulingTime + repeats:(BOOL)repeats) { - RCT_EXPORT(); - if (jsDuration == 0 && repeats == NO) { // For super fast, one-off timers, just enqueue them immediately rather than waiting a frame. [_bridge enqueueJSCall:@"RCTJSTimers.callTimers" args:@[@[callbackID]]]; return; } - NSTimeInterval interval = jsDuration / 1000; - NSTimeInterval jsCreationTimeSinceUnixEpoch = jsSchedulingTime / 1000; - NSTimeInterval currentTimeSinceUnixEpoch = [[NSDate date] timeIntervalSince1970]; - NSTimeInterval jsSchedulingOverhead = currentTimeSinceUnixEpoch - jsCreationTimeSinceUnixEpoch; + NSTimeInterval jsSchedulingOverhead = -jsSchedulingTime.timeIntervalSinceNow; if (jsSchedulingOverhead < 0) { RCTLogWarn(@"jsSchedulingOverhead (%ims) should be positive", (int)(jsSchedulingOverhead * 1000)); } - NSTimeInterval targetTime = interval - jsSchedulingOverhead; - if (interval < 0.018) { // Make sure short intervals run each frame - interval = 0; + NSTimeInterval targetTime = jsDuration - jsSchedulingOverhead; + if (jsDuration < 0.018) { // Make sure short intervals run each frame + jsDuration = 0; } RCTTimer *timer = [[RCTTimer alloc] initWithCallbackID:callbackID - interval:interval + interval:jsDuration targetTime:targetTime repeats:repeats]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -201,10 +196,8 @@ RCT_IMPORT_METHOD(RCTJSTimers, callTimers) }); } -- (void)deleteTimer:(NSNumber *)timerID +RCT_EXPORT_METHOD(deleteTimer:(NSNumber *)timerID) { - RCT_EXPORT(); - if (timerID) { dispatch_async(dispatch_get_main_queue(), ^{ _timers[timerID] = nil; diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 1ecc868b5..1fe672d8b 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -195,10 +195,10 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio NSUInteger _rootTag; } -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + /** * Declared in RCTBridge. */ @@ -514,10 +514,8 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) * A method to be called from JS, which takes a container ID and then releases * all subviews for that container upon receipt. */ -- (void)removeSubviewsFromContainerWithID:(NSNumber *)containerID +RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(NSNumber *)containerID) { - RCT_EXPORT(); - id container = _shadowViewRegistry[containerID]; RCTAssert(container != nil, @"container view (for ID %@) not found", containerID); @@ -571,10 +569,8 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) } } -- (void)removeRootView:(NSNumber *)rootReactTag +RCT_EXPORT_METHOD(removeRootView:(NSNumber *)rootReactTag) { - RCT_EXPORT(); - RCTShadowView *rootShadowView = _shadowViewRegistry[rootReactTag]; RCTAssert(rootShadowView.superview == nil, @"root view cannot have superview (ID %@)", rootReactTag); [self _purgeChildren:rootShadowView.reactSubviews fromRegistry:_shadowViewRegistry]; @@ -589,10 +585,8 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) }]; } -- (void)replaceExistingNonRootView:(NSNumber *)reactTag withView:(NSNumber *)newReactTag +RCT_EXPORT_METHOD(replaceExistingNonRootView:(NSNumber *)reactTag withView:(NSNumber *)newReactTag) { - RCT_EXPORT(); - RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; RCTAssert(shadowView != nil, @"shadowView (for ID %@) not found", reactTag); @@ -611,15 +605,13 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) removeAtIndices:removeAtIndices]; } -- (void)manageChildren:(NSNumber *)containerReactTag - moveFromIndices:(NSArray *)moveFromIndices - moveToIndices:(NSArray *)moveToIndices - addChildReactTags:(NSArray *)addChildReactTags - addAtIndices:(NSArray *)addAtIndices - removeAtIndices:(NSArray *)removeAtIndices +RCT_EXPORT_METHOD(manageChildren:(NSNumber *)containerReactTag + moveFromIndices:(NSArray *)moveFromIndices + moveToIndices:(NSArray *)moveToIndices + addChildReactTags:(NSArray *)addChildReactTags + addAtIndices:(NSArray *)addAtIndices + removeAtIndices:(NSArray *)removeAtIndices) { - RCT_EXPORT(); - [self _manageChildren:containerReactTag moveFromIndices:moveFromIndices moveToIndices:moveToIndices @@ -629,7 +621,6 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) registry:_shadowViewRegistry]; [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ - [uiManager _manageChildren:containerReactTag moveFromIndices:moveFromIndices moveToIndices:moveToIndices @@ -738,12 +729,10 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView [shadowView updateLayout]; } -- (void)createAndRegisterViewWithReactTag:(NSNumber *)reactTag - viewName:(NSString *)viewName - props:(NSDictionary *)props +RCT_EXPORT_METHOD(createView:(NSNumber *)reactTag + viewName:(NSString *)viewName + props:(NSDictionary *)props) { - RCT_EXPORT(createView); - RCTViewManager *manager = _viewManagers[viewName]; if (manager == nil) { RCTLogWarn(@"No manager class found for view with module name \"%@\"", viewName); @@ -795,10 +784,10 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView }]; } // TODO: remove viewName param as it isn't needed -- (void)updateView:(NSNumber *)reactTag viewName:(__unused NSString *)_ props:(NSDictionary *)props +RCT_EXPORT_METHOD(updateView:(NSNumber *)reactTag + viewName:(__unused NSString *)_ + props:(NSDictionary *)props) { - RCT_EXPORT(); - RCTViewManager *viewManager = _viewManagerRegistry[reactTag]; NSString *viewName = RCTViewNameForModuleName(RCTBridgeModuleNameForClass([viewManager class])); @@ -811,10 +800,8 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView }]; } -- (void)becomeResponder:(NSNumber *)reactTag +RCT_EXPORT_METHOD(focus:(NSNumber *)reactTag) { - RCT_EXPORT(focus); - if (!reactTag) return; [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { UIView *newResponder = viewRegistry[reactTag]; @@ -824,10 +811,8 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView }]; } -- (void)resignResponder:(NSNumber *)reactTag +RCT_EXPORT_METHOD(blur:(NSNumber *)reactTag) { - RCT_EXPORT(blur); - if (!reactTag) return; [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ UIView *currentResponder = viewRegistry[reactTag]; @@ -892,10 +877,9 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView }); } -- (void)measure:(NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(measure:(NSNumber *)reactTag + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - if (!callback) { RCTLogError(@"Called measure with no callback"); return; @@ -968,13 +952,11 @@ static void RCTMeasureLayout(RCTShadowView *view, * anything on the main UI thread. Invokes supplied callback with (x, y, width, * height). */ -- (void)measureLayout:(NSNumber *)reactTag - relativeTo:(NSNumber *)ancestorReactTag - errorCallback:(RCTResponseSenderBlock)errorCallback - callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(measureLayout:(NSNumber *)reactTag + relativeTo:(NSNumber *)ancestorReactTag + errorCallback:(RCTResponseSenderBlock)errorCallback + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; RCTShadowView *ancestorShadowView = _shadowViewRegistry[ancestorReactTag]; RCTMeasureLayout(shadowView, ancestorShadowView, callback); @@ -987,12 +969,10 @@ static void RCTMeasureLayout(RCTShadowView *view, * anything on the main UI thread. Invokes supplied callback with (x, y, width, * height). */ -- (void)measureLayoutRelativeToParent:(NSNumber *)reactTag - errorCallback:(RCTResponseSenderBlock)errorCallback - callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(measureLayoutRelativeToParent:(NSNumber *)reactTag + errorCallback:(RCTResponseSenderBlock)errorCallback + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; RCTMeasureLayout(shadowView, shadowView.reactSuperview, callback); } @@ -1004,13 +984,11 @@ static void RCTMeasureLayout(RCTShadowView *view, * Only layouts for views that are within the rect passed in are returned. Invokes the error callback if the * passed in parent view does not exist. Invokes the supplied callback with the array of computed layouts. */ -- (void)measureViewsInRect:(NSDictionary *)rect - parentView:(NSNumber *)reactTag - errorCallback:(RCTResponseSenderBlock)errorCallback - callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(measureViewsInRect:(NSDictionary *)rect + parentView:(NSNumber *)reactTag + errorCallback:(RCTResponseSenderBlock)errorCallback + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; if (!shadowView) { RCTLogError(@"Attempting to measure view that does not exist (tag #%@)", reactTag); @@ -1050,10 +1028,8 @@ static void RCTMeasureLayout(RCTShadowView *view, callback(@[results]); } -- (void)setMainScrollViewTag:(NSNumber *)reactTag +RCT_EXPORT_METHOD(setMainScrollViewTag:(NSNumber *)reactTag) { - RCT_EXPORT(); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ // - There should be at most one designated "main scroll view" // - There should be at most one designated "`nativeMainScrollDelegate`" @@ -1076,10 +1052,10 @@ static void RCTMeasureLayout(RCTShadowView *view, }]; } -- (void)scrollToOffsetWithView:(NSNumber *)reactTag scrollToOffsetX:(NSNumber *)offsetX offsetY:(NSNumber *)offsetY +RCT_EXPORT_METHOD(scrollTo:(NSNumber *)reactTag + withOffsetX:(NSNumber *)offsetX + offsetY:(NSNumber *)offsetY) { - RCT_EXPORT(scrollTo); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ UIView *view = viewRegistry[reactTag]; if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) { @@ -1090,10 +1066,10 @@ static void RCTMeasureLayout(RCTShadowView *view, }]; } -- (void)scrollWithoutAnimationToOffsetWithView:(NSNumber *)reactTag scrollToOffsetX:(NSNumber *)offsetX offsetY:(NSNumber *)offsetY +RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(NSNumber *)reactTag + offsetX:(NSNumber *)offsetX + offsetY:(NSNumber *)offsetY) { - RCT_EXPORT(scrollWithoutAnimationTo); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ UIView *view = viewRegistry[reactTag]; if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) { @@ -1104,10 +1080,9 @@ static void RCTMeasureLayout(RCTShadowView *view, }]; } -- (void)zoomToRectWithView:(NSNumber *)reactTag rect:(NSDictionary *)rectDict +RCT_EXPORT_METHOD(zoomToRect:(NSNumber *)reactTag + withRect:(NSDictionary *)rectDict) { - RCT_EXPORT(zoomToRect); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ UIView *view = viewRegistry[reactTag]; if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) { @@ -1122,10 +1097,8 @@ static void RCTMeasureLayout(RCTShadowView *view, * JS sets what *it* considers to be the responder. Later, scroll views can use * this in order to determine if scrolling is appropriate. */ -- (void)setJSResponder:(NSNumber *)reactTag +RCT_EXPORT_METHOD(setJSResponder:(NSNumber *)reactTag) { - RCT_EXPORT(); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { _jsResponder = viewRegistry[reactTag]; if (!_jsResponder) { @@ -1134,10 +1107,8 @@ static void RCTMeasureLayout(RCTShadowView *view, }]; } -- (void)clearJSResponder +RCT_EXPORT_METHOD(clearJSResponder) { - RCT_EXPORT(); - [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { _jsResponder = nil; }]; @@ -1407,12 +1378,10 @@ static void RCTMeasureLayout(RCTShadowView *view, return allJSConstants; } -- (void)configureNextLayoutAnimation:(NSDictionary *)config - withCallback:(RCTResponseSenderBlock)callback - errorCallback:(RCTResponseSenderBlock)errorCallback +RCT_EXPORT_METHOD(configureNextLayoutAnimation:(NSDictionary *)config + withCallback:(RCTResponseSenderBlock)callback + errorCallback:(RCTResponseSenderBlock)errorCallback) { - RCT_EXPORT(); - if (_nextLayoutAnimation) { RCTLogWarn(@"Warning: Overriding previous layout animation with new one before the first began:\n%@ -> %@.", _nextLayoutAnimation, config); @@ -1424,10 +1393,8 @@ static void RCTMeasureLayout(RCTShadowView *view, callback:callback]; } -- (void)startOrResetInteractionTiming +RCT_EXPORT_METHOD(startOrResetInteractionTiming) { - RCT_EXPORT(); - NSSet *rootViewTags = [_rootViewTags copy]; [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { for (NSNumber *reactTag in rootViewTags) { @@ -1439,11 +1406,9 @@ static void RCTMeasureLayout(RCTShadowView *view, }]; } -- (void)endAndResetInteractionTiming:(RCTResponseSenderBlock)onSuccess - onError:(RCTResponseSenderBlock)onError +RCT_EXPORT_METHOD(endAndResetInteractionTiming:(RCTResponseSenderBlock)onSuccess + onError:(RCTResponseSenderBlock)onError) { - RCT_EXPORT(); - NSSet *rootViewTags = [_rootViewTags copy]; [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { NSMutableDictionary *timingData = [[NSMutableDictionary alloc] init]; diff --git a/React/Views/RCTNavigatorManager.m b/React/Views/RCTNavigatorManager.m index b508d6318..730380bf9 100644 --- a/React/Views/RCTNavigatorManager.m +++ b/React/Views/RCTNavigatorManager.m @@ -36,12 +36,10 @@ RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack, NSInteger) } // TODO: remove error callbacks -- (void)requestSchedulingJavaScriptNavigation:(NSNumber *)reactTag - errorCallback:(RCTResponseSenderBlock)errorCallback - callback:(__unused RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(requestSchedulingJavaScriptNavigation:(NSNumber *)reactTag + errorCallback:(RCTResponseSenderBlock)errorCallback + callback:(__unused RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ RCTNavigator *navigator = viewRegistry[reactTag]; if ([navigator isKindOfClass:[RCTNavigator class]]) { diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m index 9274b46cb..ededf5f7f 100644 --- a/React/Views/RCTScrollViewManager.m +++ b/React/Views/RCTScrollViewManager.m @@ -65,11 +65,9 @@ RCT_DEPRECATED_VIEW_PROPERTY(throttleScrollCallbackMS, scrollEventThrottle) }; } -- (void)getContentSize:(NSNumber *)reactTag - callback:(RCTResponseSenderBlock)callback +RCT_EXPORT_METHOD(getContentSize:(NSNumber *)reactTag + callback:(RCTResponseSenderBlock)callback) { - RCT_EXPORT(); - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { UIView *view = viewRegistry[reactTag]; diff --git a/React/Views/RCTTabBarManager.m b/React/Views/RCTTabBarManager.m index 973a1c972..c7dfe09e1 100644 --- a/React/Views/RCTTabBarManager.m +++ b/React/Views/RCTTabBarManager.m @@ -14,10 +14,10 @@ @implementation RCTTabBarManager -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTTabBar alloc] initWithEventDispatcher:_bridge.eventDispatcher]; diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 330a597f8..9758a0944 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -19,10 +19,10 @@ @implementation RCTViewManager -RCT_EXPORT_MODULE() - @synthesize bridge = _bridge; +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTView alloc] init]; diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m index 0843f25ba..e25a7da68 100644 --- a/React/Views/RCTWebViewManager.m +++ b/React/Views/RCTWebViewManager.m @@ -43,10 +43,8 @@ RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL); }; } -- (void)goBack:(NSNumber *)reactTag +RCT_EXPORT_METHOD(goBack:(NSNumber *)reactTag) { - RCT_EXPORT(); - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTWebView *view = viewRegistry[reactTag]; if (![view isKindOfClass:[RCTWebView class]]) { @@ -56,10 +54,8 @@ RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL); }]; } -- (void)goForward:(NSNumber *)reactTag +RCT_EXPORT_METHOD(goForward:(NSNumber *)reactTag) { - RCT_EXPORT(); - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { id view = viewRegistry[reactTag]; if (![view isKindOfClass:[RCTWebView class]]) { @@ -70,10 +66,8 @@ RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL); } -- (void)reload:(NSNumber *)reactTag +RCT_EXPORT_METHOD(reload:(NSNumber *)reactTag) { - RCT_EXPORT(); - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTWebView *view = viewRegistry[reactTag]; if (![view isKindOfClass:[RCTWebView class]]) {