diff --git a/packages/react-native/Libraries/Image/RCTImageLoader.mm b/packages/react-native/Libraries/Image/RCTImageLoader.mm index 5cba225f0164..dee2685a1211 100644 --- a/packages/react-native/Libraries/Image/RCTImageLoader.mm +++ b/packages/react-native/Libraries/Image/RCTImageLoader.mm @@ -73,7 +73,9 @@ @implementation RCTImageLoader { NSArray> * (^_loadersProvider)(RCTModuleRegistry *); NSArray> * (^_decodersProvider)(RCTModuleRegistry *); NSArray> *_loaders; + std::atomic _loadersReady; NSArray> *_decoders; + std::atomic _decodersReady; NSOperationQueue *_imageDecodeQueue; dispatch_queue_t _URLRequestQueue; id _imageCache; @@ -161,23 +163,17 @@ - (void)setImageCache:(id)cache _imageCache = cache; } -- (id)imageURLLoaderForURL:(NSURL *)URL +- (NSArray> *)loaders { - if (!_isLoaderSetup) { - [self setUp]; - } - - if (!_loaders) { - std::unique_lock guard(_loadersMutex); - if (!_loaders) { - // Get loaders, sorted in reverse priority order (highest priority first) + if (!_loadersReady.load(std::memory_order_acquire)) { + std::lock_guard guard(_loadersMutex); + if (!_loadersReady.load(std::memory_order_relaxed)) { if (_loadersProvider) { _loaders = _loadersProvider(self.moduleRegistry); } 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; @@ -190,14 +186,54 @@ - (void)setImageCache:(id)cache return NSOrderedSame; } }]; + _loadersReady.store(YES, std::memory_order_release); } } + return _loaders; +} + +- (NSArray> *)decoders +{ + if (!_decodersReady.load(std::memory_order_acquire)) { + std::lock_guard guard(_loadersMutex); + if (!_decodersReady.load(std::memory_order_relaxed)) { + if (_decodersProvider) { + _decoders = _decodersProvider(self.moduleRegistry); + } else { + RCTAssert(_bridge, @"Trying to find RCTImageDataDecoders and bridge not set."); + _decoders = [_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)]; + } + _decoders = [_decoders + sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { + float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0; + float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0; + if (priorityA > priorityB) { + return NSOrderedAscending; + } else if (priorityA < priorityB) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + _decodersReady.store(YES, std::memory_order_release); + } + } + return _decoders; +} + +- (id)imageURLLoaderForURL:(NSURL *)URL +{ + if (!_isLoaderSetup) { + [self setUp]; + } + + NSArray> *loaders = [self loaders]; if (RCT_DEBUG) { // Check for handler conflicts float previousPriority = 0; id previousLoader = nil; - for (id loader in _loaders) { + for (id loader in loaders) { float priority = [loader respondsToSelector:@selector(loaderPriority)] ? [loader loaderPriority] : 0; if (previousLoader && priority < previousPriority) { return previousLoader; @@ -224,7 +260,7 @@ - (void)setImageCache:(id)cache } // Normal code path - for (id loader in _loaders) { + for (id loader in loaders) { if ([loader canLoadImageURL:URL]) { return loader; } @@ -240,35 +276,13 @@ - (void)setImageCache:(id)cache [self setUp]; } - if (!_decoders) { - // Get decoders, sorted in reverse priority order (highest priority first) - - if (_decodersProvider) { - _decoders = _decodersProvider(self.moduleRegistry); - } else { - RCTAssert(_bridge, @"Trying to find RCTImageDataDecoders and bridge not set."); - _decoders = [_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)]; - } - - _decoders = [_decoders - sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { - float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0; - float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0; - if (priorityA > priorityB) { - return NSOrderedAscending; - } else if (priorityA < priorityB) { - return NSOrderedDescending; - } else { - return NSOrderedSame; - } - }]; - } + NSArray> *decoders = [self decoders]; if (RCT_DEBUG) { // Check for handler conflicts float previousPriority = 0; id previousDecoder = nil; - for (id decoder in _decoders) { + for (id decoder in decoders) { float priority = [decoder respondsToSelector:@selector(decoderPriority)] ? [decoder decoderPriority] : 0; if (previousDecoder && priority < previousPriority) { return previousDecoder; @@ -297,7 +311,7 @@ - (void)setImageCache:(id)cache } // Normal code path - for (id decoder in _decoders) { + for (id decoder in decoders) { if ([decoder canDecodeImageData:data]) { return decoder; } @@ -1173,7 +1187,10 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request return NO; } - for (id loader in _loaders) { + if (!_isLoaderSetup) { + [self setUp]; + } + for (id loader in [self loaders]) { // Don't use RCTImageURLLoader protocol for modules that already conform to // RCTURLRequestHandler as it's inefficient to decode an image and then // convert it back into data