From 261f9434e54274a68d2cb50644c436197ef48baa Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 17 Aug 2015 04:38:19 -0700 Subject: [PATCH] Avoid dispatch_async in RCTRootView when bridge has already started Summary: There's no good reason for initialProperties to be mutable after the RCTRootView has been created. Passing it in through the constructor means we can skip one dispatch_async. --- Examples/UIExplorer/UIExplorer/AppDelegate.m | 3 +- .../UIExplorerUnitTests/RCTAllocationTests.m | 3 +- Libraries/RCTTest/RCTTestRunner.m | 3 +- React/Base/RCTRootView.h | 6 ++- React/Base/RCTRootView.m | 41 ++++++++++--------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m index f2a83422b..5a3a7d87d 100644 --- a/Examples/UIExplorer/UIExplorer/AppDelegate.m +++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m @@ -30,7 +30,8 @@ launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge - moduleName:@"UIExplorerApp"]; + moduleName:@"UIExplorerApp" + initialProperties:nil]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [[UIViewController alloc] init]; diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m index 7fe2a7445..b17fd3ddc 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m @@ -82,6 +82,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a @autoreleasepool { RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:nil moduleName:@"" + initialProperties:nil launchOptions:nil]; weakBridge = view.bridge; XCTAssertNotNil(weakBridge, @"RCTBridge should have been created"); @@ -180,7 +181,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a launchOptions:nil]; __weak UIView *rootContentView; @autoreleasepool { - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@""]; + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"" initialProperties:nil]; RUN_RUNLOOP_WHILE(!(rootContentView = [rootView valueForKey:@"contentView"])) XCTAssertTrue(rootContentView.userInteractionEnabled, @"RCTContentView should be valid"); (void)rootView; diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m index f270c3b81..d0326112f 100644 --- a/Libraries/RCTTest/RCTTestRunner.m +++ b/Libraries/RCTTest/RCTTestRunner.m @@ -87,8 +87,7 @@ RCT_NOT_IMPLEMENTED(-init) moduleProvider:_moduleProvider launchOptions:nil]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName]; - rootView.initialProperties = initialProps; + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps]; rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices NSString *testModuleName = RCTBridgeModuleNameForClass([RCTTestModule class]); diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h index d18ac176c..80f86d0cb 100644 --- a/React/Base/RCTRootView.h +++ b/React/Base/RCTRootView.h @@ -29,7 +29,8 @@ extern NSString *const RCTContentDidAppearNotification; * - Designated initializer - */ - (instancetype)initWithBridge:(RCTBridge *)bridge - moduleName:(NSString *)moduleName NS_DESIGNATED_INITIALIZER; + moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties NS_DESIGNATED_INITIALIZER; /** * - Convenience initializer - @@ -40,6 +41,7 @@ extern NSString *const RCTContentDidAppearNotification; */ - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions; /** @@ -60,7 +62,7 @@ extern NSString *const RCTContentDidAppearNotification; * The default properties to apply to the view when the script bundle * is first loaded. Defaults to nil/empty. */ -@property (nonatomic, copy) NSDictionary *initialProperties; +@property (nonatomic, copy, readonly) NSDictionary *initialProperties; /** * The class of the RCTJavaScriptExecutor to use with this view. diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index a804c810b..e2ae3e60d 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -58,6 +58,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat - (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties { RCTAssertMainThread(); RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView"); @@ -69,6 +70,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat _bridge = bridge; _moduleName = moduleName; + _initialProperties = [initialProperties copy]; _loadingViewFadeDelay = 0.25; _loadingViewFadeDuration = 0.25; @@ -81,7 +83,7 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat selector:@selector(hideLoadingView) name:RCTContentDidAppearNotification object:self]; - if (!_bridge.batchedBridge.isLoading) { + if (!_bridge.loading) { [self bundleFinishedLoading:_bridge.batchedBridge]; } @@ -92,13 +94,14 @@ NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotificat - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions { RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL moduleProvider:nil launchOptions:launchOptions]; - return [self initWithBridge:bridge moduleName:moduleName]; + return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; } RCT_NOT_IMPLEMENTED(-initWithFrame:(CGRect)frame) @@ -158,30 +161,30 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder) - (void)javaScriptDidLoad:(NSNotification *)notification { RCTBridge *bridge = notification.userInfo[@"bridge"]; - [self bundleFinishedLoading:bridge]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self bundleFinishedLoading:bridge]; + }); } - (void)bundleFinishedLoading:(RCTBridge *)bridge { - dispatch_async(dispatch_get_main_queue(), ^{ - if (!bridge.isValid) { - return; - } + if (!bridge.valid) { + return; + } - [_contentView removeFromSuperview]; - _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge]; - _contentView.backgroundColor = self.backgroundColor; - [self insertSubview:_contentView atIndex:0]; + [_contentView removeFromSuperview]; + _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge]; + _contentView.backgroundColor = self.backgroundColor; + [self insertSubview:_contentView atIndex:0]; - NSString *moduleName = _moduleName ?: @""; - NSDictionary *appParameters = @{ - @"rootTag": _contentView.reactTag, - @"initialProps": _initialProperties ?: @{}, - }; + NSString *moduleName = _moduleName ?: @""; + NSDictionary *appParameters = @{ + @"rootTag": _contentView.reactTag, + @"initialProps": _initialProperties ?: @{}, + }; - [bridge enqueueJSCall:@"AppRegistry.runApplication" - args:@[moduleName, appParameters]]; - }); + [bridge enqueueJSCall:@"AppRegistry.runApplication" + args:@[moduleName, appParameters]]; } - (void)layoutSubviews