From a794088bc79eecc52c5a581aececd07743fe7b60 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Sat, 11 Aug 2018 19:06:43 +0800 Subject: [PATCH 1/2] Revert the hack code for FLAnimatedImage compatible, because of the FLAnimatedImage initializer method block main queue. --- .../FLAnimatedImageView+WebCache.m | 49 ++++++++++++------- SDWebImage/UIView+WebCache.h | 2 +- SDWebImage/UIView+WebCache.m | 19 ++++++- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m index 99c1d033..7b787bc5 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -113,6 +113,7 @@ static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageV options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { + dispatch_group_t group = dispatch_group_create(); __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder @@ -121,6 +122,7 @@ static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageV setImageBlock:^(UIImage *image, NSData *imageData) { __strong typeof(weakSelf)strongSelf = weakSelf; if (!strongSelf) { + dispatch_group_leave(group); return; } // Step 1. Check memory cache (associate object) @@ -130,6 +132,7 @@ static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageV // FLAnimatedImage framework contains a bug that cause GIF been rotated if previous rendered image orientation is not Up. We have to call `setImage:` with non-nil image to reset the state. See `https://github.com/rs/SDWebImage/issues/2402` strongSelf.image = associatedAnimatedImage.posterImage; strongSelf.animatedImage = associatedAnimatedImage; + dispatch_group_leave(group); return; } // Step 2. Check if original compressed image data is "GIF" @@ -137,29 +140,39 @@ static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageV if (!isGIF) { strongSelf.image = image; strongSelf.animatedImage = nil; + dispatch_group_leave(group); return; } - // Step 3. Check if data exist or query disk cache - if (!imageData) { - NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; - imageData = [[SDImageCache sharedImageCache] diskImageDataForKey:key]; - } - // Step 4. Create FLAnimatedImage - FLAnimatedImage *animatedImage = SDWebImageCreateFLAnimatedImage(strongSelf, imageData); - // Step 5. Set animatedImage or normal image - if (animatedImage) { - if (strongSelf.sd_cacheFLAnimatedImage) { - image.sd_FLAnimatedImage = animatedImage; + // Hack, mark we need should use dispatch group notify for completedBlock + objc_setAssociatedObject(group, &SDWebImageInternalSetImageGroupKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + // Step 3. Check if data exist or query disk cache + __block NSData *gifData = imageData; + if (!gifData) { + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; + gifData = [[SDImageCache sharedImageCache] diskImageDataForKey:key]; } - strongSelf.image = animatedImage.posterImage; - strongSelf.animatedImage = animatedImage; - } else { - strongSelf.image = image; - strongSelf.animatedImage = nil; - } + // Step 4. Create FLAnimatedImage + FLAnimatedImage *animatedImage = SDWebImageCreateFLAnimatedImage(strongSelf, gifData); + dispatch_async(dispatch_get_main_queue(), ^{ + // Step 5. Set animatedImage or normal image + if (animatedImage) { + if (strongSelf.sd_cacheFLAnimatedImage) { + image.sd_FLAnimatedImage = animatedImage; + } + strongSelf.image = animatedImage.posterImage; + strongSelf.animatedImage = animatedImage; + } else { + strongSelf.image = image; + strongSelf.animatedImage = nil; + } + dispatch_group_leave(group); + }); + }); } progress:progressBlock - completed:completedBlock]; + completed:completedBlock + context:@{SDWebImageInternalSetImageGroupKey : group}]; } @end diff --git a/SDWebImage/UIView+WebCache.h b/SDWebImage/UIView+WebCache.h index 026f1b3c..85cb2c6d 100644 --- a/SDWebImage/UIView+WebCache.h +++ b/SDWebImage/UIView+WebCache.h @@ -13,7 +13,7 @@ /** A Dispatch group to maintain setImageBlock and completionBlock. This key should be used only internally and may be changed in the future. (dispatch_group_t) */ -FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageInternalSetImageGroupKey __deprecated_msg("Key Deprecated. Does nothing. This key should be used only internally"); +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageInternalSetImageGroupKey; /** A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) */ diff --git a/SDWebImage/UIView+WebCache.m b/SDWebImage/UIView+WebCache.m index 88def759..112a5e1d 100644 --- a/SDWebImage/UIView+WebCache.m +++ b/SDWebImage/UIView+WebCache.m @@ -64,7 +64,11 @@ static char TAG_ACTIVITY_SHOW; [self sd_cancelImageLoadOperationWithKey:validOperationKey]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + dispatch_group_t group = context[SDWebImageInternalSetImageGroupKey]; if (!(options & SDWebImageDelayPlaceholder)) { + if (group) { + dispatch_group_enter(group); + } dispatch_main_async_safe(^{ [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; }); @@ -147,12 +151,25 @@ static char TAG_ACTIVITY_SHOW; } #endif dispatch_main_async_safe(^{ + if (group) { + dispatch_group_enter(group); + } #if SD_UIKIT || SD_MAC [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; #else [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock]; #endif - callCompletedBlockClojure(); + if (group) { + // compatible code for FLAnimatedImage, because we assume completedBlock called after image was set. This will be removed in 5.x + BOOL shouldUseGroup = [objc_getAssociatedObject(group, &SDWebImageInternalSetImageGroupKey) boolValue]; + if (shouldUseGroup) { + dispatch_group_notify(group, dispatch_get_main_queue(), callCompletedBlockClojure); + } else { + callCompletedBlockClojure(); + } + } else { + callCompletedBlockClojure(); + } }); }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; From 14391eb45edd510479bc23352fb50678f00e895b Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 16 Aug 2018 17:54:45 +0800 Subject: [PATCH 2/2] Ignore to query disk cache when the image for FLAnimatedImageView+WebCache is placeholder --- SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m index 7b787bc5..2b702b20 100644 --- a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -137,7 +137,9 @@ static inline FLAnimatedImage * SDWebImageCreateFLAnimatedImage(FLAnimatedImageV } // Step 2. Check if original compressed image data is "GIF" BOOL isGIF = (image.sd_imageFormat == SDImageFormatGIF || [NSData sd_imageFormatForImageData:imageData] == SDImageFormatGIF); - if (!isGIF) { + // Check if placeholder, which does not trigger a backup disk cache query + BOOL isPlaceholder = (image == placeholder); + if (!isGIF || isPlaceholder) { strongSelf.image = image; strongSelf.animatedImage = nil; dispatch_group_leave(group);