From edb6fa79791beb804e450ca4a562a248abf730e5 Mon Sep 17 00:00:00 2001 From: Paige Sun Date: Fri, 23 Oct 2020 19:10:16 -0700 Subject: [PATCH] Synchronize RCTImageLoader loaders initialization Summary: The method `imageURLLoaderForURL` can be called from multiple threads. This adds a mutex to make sure that _loaders is initialized with a non-nil value only once. We'll only lock this mutex at one point in time as long as `_loadersProvider()` gives a value, so the mutex doesn't affect performance. Changelog: [iOS][Fixed] Synchronize RCTImageLoader loaders initialization Reviewed By: fkgozali Differential Revision: D24513083 fbshipit-source-id: b89ef8a82729eda508162b01f7fdaa8a291f40d0 --- Libraries/Image/RCTImageLoader.mm | 40 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/Libraries/Image/RCTImageLoader.mm b/Libraries/Image/RCTImageLoader.mm index 6ff74f17f15c81..7c17250f1b0f82 100644 --- a/Libraries/Image/RCTImageLoader.mm +++ b/Libraries/Image/RCTImageLoader.mm @@ -104,6 +104,7 @@ @implementation RCTImageLoader NSMutableArray *_pendingDecodes; NSInteger _scheduledDecodes; NSUInteger _activeBytes; + std::mutex _loadersMutex; __weak id _redirectDelegate; } @@ -184,26 +185,29 @@ - (void)setImageCache:(id)cache } if (!_loaders) { - // Get loaders, sorted in reverse priority order (highest priority first) - - if (_loadersProvider) { - _loaders = _loadersProvider(); - } else { - RCTAssert(_bridge, @"Trying to find RCTImageURLLoaders and bridge not set."); - _loaders = [_bridge modulesConformingToProtocol:@protocol(RCTImageURLLoader)]; - } - - _loaders = [_loaders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { - float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0; - float priorityB = [b respondsToSelector:@selector(loaderPriority)] ? [b loaderPriority] : 0; - if (priorityA > priorityB) { - return NSOrderedAscending; - } else if (priorityA < priorityB) { - return NSOrderedDescending; + std::unique_lock guard(_loadersMutex); + if (!_loaders) { + + // Get loaders, sorted in reverse priority order (highest priority first) + if (_loadersProvider) { + _loaders = _loadersProvider(); } else { - return NSOrderedSame; + RCTAssert(_bridge, @"Trying to find RCTImageURLLoaders and bridge not set."); + _loaders = [_bridge modulesConformingToProtocol:@protocol(RCTImageURLLoader)]; } - }]; + + _loaders = [_loaders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { + float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0; + float priorityB = [b respondsToSelector:@selector(loaderPriority)] ? [b loaderPriority] : 0; + if (priorityA > priorityB) { + return NSOrderedAscending; + } else if (priorityA < priorityB) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + } } if (RCT_DEBUG) {