From 5d18e9aa1672b3210c3b408ffbbdcd1bc50a29db Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 17 Jun 2019 21:15:36 -0700 Subject: [PATCH] Fabric: Workaround for weird crash in RCTImageManager Summary: Seems RCTImageLoader is not thread-safe, so we need to compensate for this for now. Classic RN mostly accesses the loader from the main thread (non-concurrently), so it mostly works for Paper. Reviewed By: mdvacca Differential Revision: D15867574 fbshipit-source-id: 4aad5570b57a136aa0bbe31d65f1afe2ae6e380e --- .../imagemanager/platform/ios/RCTImageManager.mm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.mm b/ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.mm index 420faa24c2e..c319cd30d56 100644 --- a/ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.mm +++ b/ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.mm @@ -20,11 +20,15 @@ using namespace facebook::react; @implementation RCTImageManager { RCTImageLoader *_imageLoader; + dispatch_queue_t _backgroundSerialQueue; } -- (instancetype)initWithImageLoader:(RCTImageLoader *)imageLoader { +- (instancetype)initWithImageLoader:(RCTImageLoader *)imageLoader +{ if (self = [super init]) { _imageLoader = imageLoader; + _backgroundSerialQueue = + dispatch_queue_create("com.facebook.react-native.image-manager-queue", DISPATCH_QUEUE_SERIAL); } return self; @@ -46,8 +50,12 @@ using namespace facebook::react; * work (such as creating an `NSURLRequest` object and some obscure logic inside `RCTImageLoader`) can take a couple * of milliseconds, so we have to offload this to a separate thread. `ImageRequest` can be created as part of the * layout process, so it must be highly performant. + * + * Technically, we don't need to dispatch this to *serial* queue. The interface of `RCTImageLoader` promises to be + * fully thread-safe. However, in reality, it crashes when we request images on concurrently on different threads. See + * T46024425 for more details. */ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(_backgroundSerialQueue, ^{ NSURLRequest *request = NSURLRequestFromImageSource(imageSource); auto completionBlock = ^(NSError *error, UIImage *image) {