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
This commit is contained in:
Pieter De Baets 2016-02-01 07:50:50 -08:00 committed by facebook-github-bot-7
parent 97723e4d7e
commit bb5a6be9dd
1 changed files with 35 additions and 25 deletions

View File

@ -483,6 +483,8 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count]; [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray<NSNumber *> *parentsAreNew = NSMutableArray<NSNumber *> *parentsAreNew =
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count]; [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableDictionary<NSNumber *, RCTViewManagerUIBlock> *updateBlocks =
[NSMutableDictionary new];
for (RCTShadowView *shadowView in viewsWithNewFrames) { for (RCTShadowView *shadowView in viewsWithNewFrames) {
[frameReactTags addObject:shadowView.reactTag]; [frameReactTags addObject:shadowView.reactTag];
@ -500,10 +502,13 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
// reactSetFrame: has been called. Note that if reactSetFrame: is not called, // 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 // these won't be called either, so this is not a suitable place to update
// properties that aren't related to layout. // properties that aren't related to layout.
NSMutableArray<RCTViewManagerUIBlock> *updateBlocks = [NSMutableArray new];
for (RCTShadowView *shadowView in viewsWithNewFrames) { for (RCTShadowView *shadowView in viewsWithNewFrames) {
RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager]; RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager];
RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView:shadowView]; RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView:shadowView];
if (block) {
updateBlocks[shadowView.reactTag] = block;
}
if (shadowView.onLayout) { if (shadowView.onLayout) {
CGRect frame = shadowView.frame; CGRect frame = shadowView.frame;
shadowView.onLayout(@{ shadowView.onLayout(@{
@ -525,14 +530,9 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
RCTAssert(view != nil, @"view (for ID %@) not found", reactTag); RCTAssert(view != nil, @"view (for ID %@) not found", reactTag);
RCTRootView *rootView = (RCTRootView *)[view superview]; RCTRootView *rootView = (RCTRootView *)[view superview];
rootView.intrinsicSize = contentSize; rootView.intrinsicSize = contentSize;
}); });
} }
if (block) {
[updateBlocks addObject:block];
}
} }
// Perform layout (possibly animated) // 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 // Animate view creation
if (createAnimation) { if (createAnimation) {
[view reactSetFrame:frame];
CATransform3D finalTransform = view.layer.transform; CATransform3D finalTransform = view.layer.transform;
CGFloat finalOpacity = view.layer.opacity; CGFloat finalOpacity = view.layer.opacity;
if ([createAnimation.property isEqualToString:@"scaleXY"]) { if ([createAnimation.property isEqualToString:@"scaleXY"]) {
@ -586,6 +572,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
} else if ([createAnimation.property isEqualToString:@"opacity"]) { } else if ([createAnimation.property isEqualToString:@"opacity"]) {
view.layer.opacity = 0.0; view.layer.opacity = 0.0;
} }
[createAnimation performAnimations:^{ [createAnimation performAnimations:^{
if ([createAnimation.property isEqual:@"scaleXY"]) { if ([createAnimation.property isEqual:@"scaleXY"]) {
view.layer.transform = finalTransform; view.layer.transform = finalTransform;
@ -595,10 +582,33 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
RCTLogError(@"Unsupported layout animation createConfig property %@", RCTLogError(@"Unsupported layout animation createConfig property %@",
createAnimation.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);
} }
} }
}; };