@@ -85,6 +85,10 @@ @interface ASMultiplexImageNode ()
8585 ASDN::RecursiveMutex _downloadIdentifierLock;
8686 id _downloadIdentifier;
8787
88+ // Properties
89+ ASDN::RecursiveMutex _propertyLock;
90+ BOOL _shouldRenderProgressImages;
91+
8892 // set on init only
8993 BOOL _downloaderSupportsNewProtocol;
9094 BOOL _downloaderImplementsSetProgress;
@@ -186,6 +190,8 @@ - (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASI
186190 _cacheSupportsNewProtocol = [cache respondsToSelector: @selector (cachedImageWithURL:callbackQueue:completion: )];
187191 _cacheSupportsClearing = [cache respondsToSelector: @selector (clearFetchedImageFromCacheWithURL: )];
188192
193+ _shouldRenderProgressImages = YES ;
194+
189195 self.shouldBypassEnsureDisplay = YES ;
190196
191197 return self;
@@ -339,6 +345,27 @@ - (void)setDataSource:(id <ASMultiplexImageNodeDataSource>)dataSource
339345 #endif
340346}
341347
348+
349+ - (void )setShouldRenderProgressImages : (BOOL )shouldRenderProgressImages
350+ {
351+ ASDN::MutexLocker l (_propertyLock);
352+ if (shouldRenderProgressImages == _shouldRenderProgressImages) {
353+ return ;
354+ }
355+
356+ _shouldRenderProgressImages = shouldRenderProgressImages;
357+
358+
359+ ASDN::MutexUnlocker u (_propertyLock);
360+ [self _updateProgressImageBlockOnDownloaderIfNeeded ];
361+ }
362+
363+ - (BOOL )shouldRenderProgressImages
364+ {
365+ ASDN::MutexLocker l (_propertyLock);
366+ return _shouldRenderProgressImages;
367+ }
368+
342369#pragma mark -
343370
344371#pragma mark -
@@ -436,8 +463,12 @@ - (UIImage *)_bestImmediatelyAvailableImageFromDataSource:(id *)imageIdentifierO
436463 }
437464
438465 // Grab the best available image from the data source.
466+ UIImage *existingImage = self.image ;
439467 for (id imageIdentifier in _imageIdentifiers) {
440- UIImage *image = [_dataSource multiplexImageNode: self imageForImageIdentifier: imageIdentifier];
468+ // If this image is already loaded, don't request it from the data source again because
469+ // the data source may generate a new instance of UIImage that returns NO for isEqual:
470+ // and we'll end up in an infinite loading loop.
471+ UIImage *image = ASObjectIsEqual (imageIdentifier, _loadedImageIdentifier) ? existingImage : [_dataSource multiplexImageNode: self imageForImageIdentifier: imageIdentifier];
441472 if (image) {
442473 if (imageIdentifierOut) {
443474 *imageIdentifierOut = imageIdentifier;
@@ -458,32 +489,34 @@ - (UIImage *)_bestImmediatelyAvailableImageFromDataSource:(id *)imageIdentifierO
458489 */
459490- (void )_updateProgressImageBlockOnDownloaderIfNeeded
460491{
461- // Read our interface state before locking so that we don't lock super while holding our lock.
462- ASInterfaceState interfaceState = self.interfaceState ;
463- ASDN::MutexLocker l (_downloadIdentifierLock);
464-
465- if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil ) {
492+ BOOL shouldRenderProgressImages = self.shouldRenderProgressImages ;
493+
494+ // Read our interface state before locking so that we don't lock super while holding our lock.
495+ ASInterfaceState interfaceState = self.interfaceState ;
496+ ASDN::MutexLocker l (_downloadIdentifierLock);
497+
498+ if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil ) {
499+ return ;
500+ }
501+
502+ ASImageDownloaderProgressImage progress = nil ;
503+ if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible (interfaceState)) {
504+ __weak __typeof__ (self) weakSelf = self;
505+ progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
506+ __typeof__ (self) strongSelf = weakSelf;
507+ if (strongSelf == nil ) {
466508 return ;
467- }
468-
469- ASImageDownloaderProgressImage progress = nil ;
470- if (ASInterfaceStateIncludesVisible (interfaceState)) {
471- __weak __typeof__ (self) weakSelf = self;
472- progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) {
473- __typeof__ (self) strongSelf = weakSelf;
474- if (strongSelf == nil ) {
475- return ;
476- }
477-
478- ASDN::MutexLocker l (strongSelf->_downloadIdentifierLock );
479- // Getting a result back for a different download identifier, download must not have been successfully canceled
480- if (ASObjectIsEqual (strongSelf->_downloadIdentifier , downloadIdentifier) == NO && downloadIdentifier != nil ) {
481- return ;
482- }
483- strongSelf.image = progressImage;
484- };
485- }
486- [_downloader setProgressImageBlock: progress callbackQueue: dispatch_get_main_queue () withDownloadIdentifier: _downloadIdentifier];
509+ }
510+
511+ ASDN::MutexLocker l (strongSelf->_downloadIdentifierLock );
512+ // Getting a result back for a different download identifier, download must not have been successfully canceled
513+ if (ASObjectIsEqual (strongSelf->_downloadIdentifier , downloadIdentifier) == NO && downloadIdentifier != nil ) {
514+ return ;
515+ }
516+ strongSelf.image = progressImage;
517+ };
518+ }
519+ [_downloader setProgressImageBlock: progress callbackQueue: dispatch_get_main_queue () withDownloadIdentifier: _downloadIdentifier];
487520}
488521
489522- (void )_clearImage
0 commit comments