From 2e7d526a6987ac5e94f35161c73e613ae7d4df50 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 4 Mar 2021 18:42:11 +0800 Subject: [PATCH] Performance enhancement: Allows to use progressive decoding image to callback the completion when finished. Which can reduce the decoding pressure and animation loading delay --- SDWebImage/Core/SDImageLoader.h | 13 +++++++++++++ SDWebImage/Core/SDImageLoader.m | 18 ++++++++++++++---- .../Core/SDWebImageDownloaderOperation.m | 11 ++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/SDWebImage/Core/SDImageLoader.h b/SDWebImage/Core/SDImageLoader.h index 25f1af40..addad836 100644 --- a/SDWebImage/Core/SDImageLoader.h +++ b/SDWebImage/Core/SDImageLoader.h @@ -9,6 +9,7 @@ #import "SDWebImageCompat.h" #import "SDWebImageDefine.h" #import "SDWebImageOperation.h" +#import "SDImageCoder.h" typedef void(^SDImageLoaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); typedef void(^SDImageLoaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); @@ -50,6 +51,18 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Non */ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, BOOL finished, id _Nonnull operation, SDWebImageOptions options, SDWebImageContext * _Nullable context); +/** + This function get the progressive decoder for current loading operation. If no progressive decoding is happended or decoder is not able to construct, return nil. + @return The progressive decoder associated with the loading operation. + */ +FOUNDATION_EXPORT id _Nullable SDImageLoaderGetProgressiveCoder(id _Nonnull operation); + +/** + This function set the progressive decoder for current loading operation. If no progressive decoding is happended, pass nil. + @param operation The loading operation to associate the progerssive decoder. + */ +FOUNDATION_EXPORT void SDImageLoaderSetProgressiveCoder(id _Nonnull operation, id _Nullable progressiveCoder); + #pragma mark - SDImageLoader /** diff --git a/SDWebImage/Core/SDImageLoader.m b/SDWebImage/Core/SDImageLoader.m index c529954e..7b565bff 100644 --- a/SDWebImage/Core/SDImageLoader.m +++ b/SDWebImage/Core/SDImageLoader.m @@ -15,8 +15,20 @@ #import "SDInternalMacros.h" #import "objc/runtime.h" +SDWebImageContextOption const SDWebImageContextLoaderCachedImage = @"loaderCachedImage"; + static void * SDImageLoaderProgressiveCoderKey = &SDImageLoaderProgressiveCoderKey; +id SDImageLoaderGetProgressiveCoder(id operation) { + NSCParameterAssert(operation); + return objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey); +} + +void SDImageLoaderSetProgressiveCoder(id operation, id progressiveCoder) { + NSCParameterAssert(operation); + objc_setAssociatedObject(operation, SDImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NSURL * _Nonnull imageURL, SDWebImageOptions options, SDWebImageContext * _Nullable context) { NSCParameterAssert(imageData); NSCParameterAssert(imageURL); @@ -136,7 +148,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im SDImageCoderOptions *coderOptions = [mutableCoderOptions copy]; // Grab the progressive image coder - id progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey); + id progressiveCoder = SDImageLoaderGetProgressiveCoder(operation); if (!progressiveCoder) { id imageCoder = context[SDWebImageContextImageCoder]; // Check the progressive coder if provided @@ -152,7 +164,7 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im } } } - objc_setAssociatedObject(operation, SDImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + SDImageLoaderSetProgressiveCoder(operation, progressiveCoder); } // If we can't find any progressive coder, disable progressive download if (!progressiveCoder) { @@ -196,5 +208,3 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im return image; } - -SDWebImageContextOption const SDWebImageContextLoaderCachedImage = @"loaderCachedImage"; diff --git a/SDWebImage/Core/SDWebImageDownloaderOperation.m b/SDWebImage/Core/SDWebImageDownloaderOperation.m index 0c21a530..92d7ad9b 100644 --- a/SDWebImage/Core/SDWebImageDownloaderOperation.m +++ b/SDWebImage/Core/SDWebImageDownloaderOperation.m @@ -11,6 +11,7 @@ #import "SDInternalMacros.h" #import "SDWebImageDownloaderResponseModifier.h" #import "SDWebImageDownloaderDecryptor.h" +#import "SDAnimatedImage.h" static NSString *const kProgressCallbackKey = @"progress"; static NSString *const kCompletedCallbackKey = @"completed"; @@ -262,6 +263,7 @@ typedef NSMutableDictionary SDCallbacksDictionary; - (void)done { self.finished = YES; self.executing = NO; + SDImageLoaderSetProgressiveCoder(self, nil); [self reset]; } @@ -471,7 +473,14 @@ didReceiveResponse:(NSURLResponse *)response // decode the image in coder queue, cancel all previous decoding process [self.coderQueue cancelAllOperations]; [self.coderQueue addOperationWithBlock:^{ - UIImage *image = SDImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + // check if we already use progressive decoding, use that to produce faster decoding + id progressiveCoder = SDImageLoaderGetProgressiveCoder(self); + UIImage *image; + if (progressiveCoder) { + image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, YES, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + } else { + image = SDImageLoaderDecodeImageData(imageData, self.request.URL, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context); + } CGSize imageSize = image.size; if (imageSize.width == 0 || imageSize.height == 0) { NSString *description = image == nil ? @"Downloaded image decode failed" : @"Downloaded image has 0 pixels";