From bb5a6be9dd996febaed5b55fb59d095f0dc4c4d3 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 1 Feb 2016 07:50:50 -0800 Subject: [PATCH] Only execute update block once Summary: We were executing all the updateBlocks for every frame that was updated in the UI flush. This would quickly give you an explosive number of block calls when loading complex views. This update block is only really used by text to propagate padding, even though the actual insets are mostly just 0. public Reviewed By: nicklockwood Differential Revision: D2848968 fb-gh-sync-id: e43c529c2bb9729e2b779bf4abefeed58775cc2e --- React/Modules/RCTUIManager.m | 60 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 9d0ea2502..d98cf7336 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -483,6 +483,8 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count]; NSMutableArray *parentsAreNew = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count]; + NSMutableDictionary *updateBlocks = + [NSMutableDictionary new]; for (RCTShadowView *shadowView in viewsWithNewFrames) { [frameReactTags addObject:shadowView.reactTag]; @@ -500,10 +502,13 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); // reactSetFrame: has been called. Note that if reactSetFrame: is not called, // these won't be called either, so this is not a suitable place to update // properties that aren't related to layout. - NSMutableArray *updateBlocks = [NSMutableArray new]; for (RCTShadowView *shadowView in viewsWithNewFrames) { RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager]; RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView:shadowView]; + if (block) { + updateBlocks[shadowView.reactTag] = block; + } + if (shadowView.onLayout) { CGRect frame = shadowView.frame; shadowView.onLayout(@{ @@ -525,14 +530,9 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); RCTAssert(view != nil, @"view (for ID %@) not found", reactTag); RCTRootView *rootView = (RCTRootView *)[view superview]; - rootView.intrinsicSize = contentSize; }); } - - if (block) { - [updateBlocks addObject:block]; - } } // Perform layout (possibly animated) @@ -561,24 +561,10 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); } }; - // Animate view update - if (updateAnimation) { - [updateAnimation performAnimations:^{ - [view reactSetFrame:frame]; - for (RCTViewManagerUIBlock block in updateBlocks) { - block(self, _viewRegistry); - } - } withCompletionBlock:completion]; - } else { - [view reactSetFrame:frame]; - for (RCTViewManagerUIBlock block in updateBlocks) { - block(self, _viewRegistry); - } - completion(YES); - } - // Animate view creation if (createAnimation) { + [view reactSetFrame:frame]; + CATransform3D finalTransform = view.layer.transform; CGFloat finalOpacity = view.layer.opacity; if ([createAnimation.property isEqualToString:@"scaleXY"]) { @@ -586,6 +572,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); } else if ([createAnimation.property isEqualToString:@"opacity"]) { view.layer.opacity = 0.0; } + [createAnimation performAnimations:^{ if ([createAnimation.property isEqual:@"scaleXY"]) { view.layer.transform = finalTransform; @@ -595,10 +582,33 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); RCTLogError(@"Unsupported layout animation createConfig property %@", createAnimation.property); } - for (RCTViewManagerUIBlock block in updateBlocks) { - block(self, _viewRegistry); + + RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag]; + if (updateBlock) { + updateBlock(self, _viewRegistry); } - } withCompletionBlock:nil]; + } withCompletionBlock:completion]; + + // Animate view update + } else if (updateAnimation) { + [updateAnimation performAnimations:^{ + [view reactSetFrame:frame]; + + RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag]; + if (updateBlock) { + updateBlock(self, _viewRegistry); + } + } withCompletionBlock:completion]; + + // Update without animation + } else { + [view reactSetFrame:frame]; + + RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag]; + if (updateBlock) { + updateBlock(self, _viewRegistry); + } + completion(YES); } } };