From dfa871b20e4c98e20b6a98ac4a058b29b4ed42e1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 30 Aug 2019 17:23:51 +0800 Subject: [PATCH 1/2] Fix that some option mask check with local BOOL variable, will result error result on 32 bit device. Use a macro help to solve this issue --- SDWebImage/Core/SDImageCacheDefine.m | 7 ++++--- SDWebImage/Core/SDImageLoader.m | 11 ++++++----- SDWebImage/Core/SDWebImageDownloader.m | 2 +- SDWebImage/Core/SDWebImageDownloaderOperation.m | 2 +- SDWebImage/Core/SDWebImageManager.m | 4 ++-- SDWebImage/Core/UIView+WebCache.m | 2 +- SDWebImage/Private/SDInternalMacros.h | 4 ++++ 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/SDWebImage/Core/SDImageCacheDefine.m b/SDWebImage/Core/SDImageCacheDefine.m index 0efa1c4d..99e57f1a 100644 --- a/SDWebImage/Core/SDImageCacheDefine.m +++ b/SDWebImage/Core/SDImageCacheDefine.m @@ -11,10 +11,11 @@ #import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+Metadata.h" +#import "SDInternalMacros.h" UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { UIImage *image; - BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly); NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; @@ -46,7 +47,7 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { - BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; + BOOL shouldDecode = !SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage); if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -55,7 +56,7 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS shouldDecode = NO; } if (shouldDecode) { - BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; + BOOL shouldScaleDown = SD_OPTIONS_CONTAINS(options, SDWebImageScaleDownLargeImages); if (shouldScaleDown) { image = [SDImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; } else { diff --git a/SDWebImage/Core/SDImageLoader.m b/SDWebImage/Core/SDImageLoader.m index ffe22354..8cbbe4e0 100644 --- a/SDWebImage/Core/SDImageLoader.m +++ b/SDWebImage/Core/SDImageLoader.m @@ -12,6 +12,7 @@ #import "SDImageCoderHelper.h" #import "SDAnimatedImage.h" #import "UIImage+Metadata.h" +#import "SDInternalMacros.h" #import "objc/runtime.h" static void * SDImageLoaderProgressiveCoderKey = &SDImageLoaderProgressiveCoderKey; @@ -28,7 +29,7 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS } else { cacheKey = imageURL.absoluteString; } - BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly); NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; @@ -60,7 +61,7 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions]; } if (image) { - BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; + BOOL shouldDecode = !SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage); if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; @@ -70,7 +71,7 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS } if (shouldDecode) { - BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; + BOOL shouldScaleDown = SD_OPTIONS_CONTAINS(options, SDWebImageScaleDownLargeImages); if (shouldScaleDown) { image = [SDImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; } else { @@ -95,7 +96,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im } else { cacheKey = imageURL.absoluteString; } - BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly); NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; @@ -142,7 +143,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions]; } if (image) { - BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; + BOOL shouldDecode = !SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage); if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; diff --git a/SDWebImage/Core/SDWebImageDownloader.m b/SDWebImage/Core/SDWebImageDownloader.m index 453c5c20..4d8a0e69 100644 --- a/SDWebImage/Core/SDWebImageDownloader.m +++ b/SDWebImage/Core/SDWebImageDownloader.m @@ -270,7 +270,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext; // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData; NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval]; - mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); + mutableRequest.HTTPShouldHandleCookies = SD_OPTIONS_CONTAINS(options, SDWebImageDownloaderHandleCookies); mutableRequest.HTTPShouldUsePipelining = YES; SD_LOCK(self.HTTPHeadersLock); mutableRequest.allHTTPHeaderFields = self.HTTPHeaders; diff --git a/SDWebImage/Core/SDWebImageDownloaderOperation.m b/SDWebImage/Core/SDWebImageDownloaderOperation.m index 4e7b64c9..c07047e5 100644 --- a/SDWebImage/Core/SDWebImageDownloaderOperation.m +++ b/SDWebImage/Core/SDWebImageDownloaderOperation.m @@ -498,7 +498,7 @@ didReceiveResponse:(NSURLResponse *)response } - (BOOL)shouldContinueWhenAppEntersBackground { - return self.options & SDWebImageDownloaderContinueInBackground; + return SD_OPTIONS_CONTAINS(self.options, SDWebImageDownloaderContinueInBackground); } - (void)callCompletionBlocksWithError:(nullable NSError *)error { diff --git a/SDWebImage/Core/SDWebImageManager.m b/SDWebImage/Core/SDWebImageManager.m index 3d5d0efb..693fa680 100644 --- a/SDWebImage/Core/SDWebImageManager.m +++ b/SDWebImage/Core/SDWebImageManager.m @@ -185,7 +185,7 @@ static id _defaultImageLoader; progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { // Check whether we should query cache - BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0; + BOOL shouldQueryCache = !SD_OPTIONS_CONTAINS(options, SDWebImageFromLoaderOnly); if (shouldQueryCache) { id cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *key = [self cacheKeyForURL:url cacheKeyFilter:cacheKeyFilter]; @@ -218,7 +218,7 @@ static id _defaultImageLoader; progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { // Check whether we should download image from network - BOOL shouldDownload = (options & SDWebImageFromCacheOnly) == 0; + BOOL shouldDownload = !SD_OPTIONS_CONTAINS(options, SDWebImageFromCacheOnly); shouldDownload &= (!cachedImage || options & SDWebImageRefreshCached); shouldDownload &= (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); shouldDownload &= [self.imageLoader canRequestImageForURL:url]; diff --git a/SDWebImage/Core/UIView+WebCache.m b/SDWebImage/Core/UIView+WebCache.m index dc5eeba7..3019b0e0 100644 --- a/SDWebImage/Core/UIView+WebCache.m +++ b/SDWebImage/Core/UIView+WebCache.m @@ -262,7 +262,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL; [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) { context.duration = transition.duration; context.timingFunction = transition.timingFunction; - context.allowsImplicitAnimation = (transition.animationOptions & SDWebImageAnimationOptionAllowsImplicitAnimation); + context.allowsImplicitAnimation = SD_OPTIONS_CONTAINS(transition.animationOptions, SDWebImageAnimationOptionAllowsImplicitAnimation); if (finalSetImageBlock && !transition.avoidAutoSetImage) { finalSetImageBlock(image, imageData, cacheType, imageURL); } diff --git a/SDWebImage/Private/SDInternalMacros.h b/SDWebImage/Private/SDInternalMacros.h index edcb1ab0..837d77b0 100644 --- a/SDWebImage/Private/SDInternalMacros.h +++ b/SDWebImage/Private/SDInternalMacros.h @@ -17,6 +17,10 @@ #define SD_UNLOCK(lock) dispatch_semaphore_signal(lock); #endif +#ifndef SD_OPTIONS_CONTAINS +#define SD_OPTIONS_CONTAINS(options, value) (((options) & (value)) == (value)) +#endif + #ifndef weakify #define weakify(...) \ sd_keywordify \ From 7bd12dac54b95e43c88ee63a3428246fc7d39a80 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 3 Sep 2019 16:38:14 +0800 Subject: [PATCH 2/2] Fix the case when SDAnimatedImageView dealloc on the fetch queue, will cause it trigger the UIKit/AppKit method on non-main queue and captured by UI Main Thread Checker --- SDWebImage/Core/SDAnimatedImageView.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SDWebImage/Core/SDAnimatedImageView.m b/SDWebImage/Core/SDAnimatedImageView.m index 0adcfd61..91416799 100644 --- a/SDWebImage/Core/SDAnimatedImageView.m +++ b/SDWebImage/Core/SDAnimatedImageView.m @@ -683,7 +683,12 @@ static NSUInteger SDDeviceFreeMemory() { if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) { // Prefetch next frame in background queue UIImage *animatedImage = self.animatedImage; + @weakify(self); NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + @strongify(self); + if (!self) { + return; + } UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex]; BOOL isAnimating = NO; @@ -697,6 +702,10 @@ static NSUInteger SDDeviceFreeMemory() { self.frameBuffer[@(fetchFrameIndex)] = frame; SD_UNLOCK(self.lock); } + // Ensure when self dealloc, it dealloced on the main queue (UIKit/AppKit rule) + dispatch_async(dispatch_get_main_queue(), ^{ + [self class]; + }); }]; [self.fetchQueue addOperation:operation]; }