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
This commit is contained in:
Paige Sun
2020-10-23 19:12:53 -07:00
committed by Facebook GitHub Bot
parent 0d1f93c317
commit edb6fa7979
+22 -18
View File
@@ -104,6 +104,7 @@ static uint64_t monotonicTimeGetCurrentNanoseconds(void)
NSMutableArray *_pendingDecodes;
NSInteger _scheduledDecodes;
NSUInteger _activeBytes;
std::mutex _loadersMutex;
__weak id<RCTImageRedirectProtocol> _redirectDelegate;
}
@@ -184,26 +185,29 @@ RCT_EXPORT_MODULE()
}
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<RCTImageURLLoader> a, id<RCTImageURLLoader> 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<std::mutex> 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<RCTImageURLLoader> a, id<RCTImageURLLoader> 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) {