Reload image without dispatch_async if completion handler is already on main thread
Summary: This works with D3305161 to minimize image flashing. After D3305161, the completion handler passed to `-[RCTImageLoader loadImageWithoutClipping:size:scale:resizeMode:progressBlock:completionBlock:]` may be called back on the main queue in the case of a cached image. In this case, we want to set the image view's image property synchronously rather than on the next runloop iteration via dispatch_async. This minimizes the amount of image flashing the user sees when displaying a cached image. The exception to this case is for blurred images. A blur can be an expensive (taking multiple ms on the CPU), so we always make sure to perform the blur off the main queue even if the image is cached and the callback came back on the main queue. Reviewed By: nicklockwood Differential Revision: D3310176 fbshipit-source-id: 6820782527b65e4956879cf06e8ed2c09c622a58
This commit is contained in:
parent
fe5c0d2d06
commit
5bb5ea7135
|
@ -207,13 +207,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
scale:imageScale
|
||||
resizeMode:(RCTResizeMode)self.contentMode
|
||||
progressBlock:progressHandler
|
||||
completionBlock:^(NSError *error, UIImage *image) {
|
||||
completionBlock:^(NSError *error, UIImage *loadedImage) {
|
||||
RCTImageView *strongSelf = weakSelf;
|
||||
if (blurRadius > __FLT_EPSILON__) {
|
||||
// Do this on the background thread to avoid blocking interaction
|
||||
image = RCTBlurredImageWithRadius(image, blurRadius);
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
void (^setImageBlock)(UIImage *) = ^(UIImage *image) {
|
||||
if (![source isEqual:strongSelf.source]) {
|
||||
// Bail out if source has changed since we started loading
|
||||
return;
|
||||
|
@ -234,9 +230,31 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
}
|
||||
}
|
||||
if (strongSelf->_onLoadEnd) {
|
||||
strongSelf->_onLoadEnd(nil);
|
||||
strongSelf->_onLoadEnd(nil);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (blurRadius > __FLT_EPSILON__) {
|
||||
// Blur on a background thread to avoid blocking interaction
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *image = RCTBlurredImageWithRadius(loadedImage, blurRadius);
|
||||
RCTExecuteOnMainThread(^{
|
||||
setImageBlock(image);
|
||||
}, NO);
|
||||
});
|
||||
} else {
|
||||
// No blur, so try to set the image on the main thread synchronously to minimize image
|
||||
// flashing. (For instance, if this view gets attached to a window, then -didMoveToWindow
|
||||
// calls -reloadImage, and we want to set the image synchronously if possible so that the
|
||||
// image property is set in the same CATransaction that attaches this view to the window.)
|
||||
if ([NSThread isMainThread]) {
|
||||
setImageBlock(loadedImage);
|
||||
} else {
|
||||
RCTExecuteOnMainThread(^{
|
||||
setImageBlock(loadedImage);
|
||||
}, NO);
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[self clearImage];
|
||||
|
|
Loading…
Reference in New Issue