Merge pull request #2261 from dreampiggy/feature_request_modifier_and_response

Feature request modifier and response
This commit is contained in:
DreamPiggy 2018-04-11 16:51:28 +08:00 committed by GitHub
commit 2cb03773db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 294 additions and 83 deletions

View File

@ -453,6 +453,18 @@
32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
32EB6D91206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
32EB6D92206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */; };
32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -1490,6 +1502,8 @@
32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = "<group>"; };
32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = "<group>"; };
32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = "<group>"; };
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = "<group>"; };
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = "<group>"; };
32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = "<group>"; };
32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = "<group>"; };
32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = "<group>"; };
@ -1984,6 +1998,8 @@
530E49E416460AE2002868E7 /* SDWebImageDownloaderOperation.m */,
32B9B535206ED4230026769D /* SDWebImageDownloaderConfig.h */,
32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */,
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */,
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */,
);
name = Downloader;
sourceTree = "<group>";
@ -2196,6 +2212,7 @@
323F8BE71F38EF770092B609 /* vp8li_enc.h in Headers */,
329A185C1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */,
4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */,
32F21B5420788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
80377DCC1F2F66A700F89830 /* lossless_common.h in Headers */,
321E60971F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */,
43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
@ -2332,6 +2349,7 @@
80377C191F2F666300F89830 /* endian_inl_utils.h in Headers */,
321E60A31F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */,
4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */,
32F21B5220788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */,
80377D621F2F66A700F89830 /* yuv.h in Headers */,
80377D341F2F66A700F89830 /* dsp.h in Headers */,
@ -2427,6 +2445,7 @@
43A62A1E1D0E0A800089D7DD /* format_constants.h in Headers */,
80377E111F2F66A800F89830 /* lossless_common.h in Headers */,
431BB6F61D06D2C1006A3455 /* UIImage+MultiFormat.h in Headers */,
32F21B5520788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
807A122C1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */,
323F8BFA1F38EF770092B609 /* animi.h in Headers */,
431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */,
@ -2460,6 +2479,7 @@
4397D2BD1D0DDD8C00BB2784 /* types.h in Headers */,
4397D2C01D0DDD8C00BB2784 /* SDWebImage.h in Headers */,
4397D2C11D0DDD8C00BB2784 /* format_constants.h in Headers */,
32F21B5620788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
80377C8D1F2F666400F89830 /* random_utils.h in Headers */,
4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */,
323F8B551F38EF770092B609 /* backward_references_enc.h in Headers */,
@ -2551,6 +2571,7 @@
323F8BE61F38EF770092B609 /* vp8li_enc.h in Headers */,
329A185B1FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */,
4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */,
32F21B5320788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
80377D871F2F66A700F89830 /* lossless_common.h in Headers */,
321E60961F38E8ED00405457 /* SDWebImageImageIOCoder.h in Headers */,
4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */,
@ -2663,6 +2684,7 @@
5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */,
4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */,
80377CEF1F2F66A100F89830 /* dsp.h in Headers */,
32F21B5120788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h in Headers */,
80377C011F2F665300F89830 /* filters_utils.h in Headers */,
5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */,
438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */,
@ -2977,6 +2999,7 @@
80377DEB1F2F66A700F89830 /* yuv.c in Sources */,
3237F9E920161AE000A88143 /* NSImage+Additions.m in Sources */,
32C0FDEA2013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
32F21B5A20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
00733A551BC4880000A5A117 /* SDWebImageDownloader.m in Sources */,
80377EB71F2F66D400F89830 /* alpha_dec.c in Sources */,
80377DC61F2F66A700F89830 /* enc.c in Sources */,
@ -3165,6 +3188,7 @@
80377D5F1F2F66A700F89830 /* yuv_mips32.c in Sources */,
80377D3C1F2F66A700F89830 /* enc.c in Sources */,
4314D13B1D0E0E3B004B36C9 /* UIButton+WebCache.m in Sources */,
32F21B5820788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
321E60C51F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
80377D461F2F66A700F89830 /* lossless_enc_neon.c in Sources */,
80377E9B1F2F66D400F89830 /* frame_dec.c in Sources */,
@ -3321,6 +3345,7 @@
80377E2E1F2F66A800F89830 /* yuv_mips32.c in Sources */,
80377E0B1F2F66A800F89830 /* enc.c in Sources */,
431BB6AC1D06D2C1006A3455 /* SDWebImageCompat.m in Sources */,
32F21B5B20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
80377E151F2F66A800F89830 /* lossless_enc_neon.c in Sources */,
321E60C81F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
80377C721F2F666400F89830 /* random_utils.c in Sources */,
@ -3475,6 +3500,7 @@
323F8BF51F38EF770092B609 /* anim_encode.c in Sources */,
80377E381F2F66A800F89830 /* argb_sse2.c in Sources */,
323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */,
32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */,
4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */,
80377E711F2F66A800F89830 /* upsampling.c in Sources */,
@ -3607,6 +3633,7 @@
43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */,
3237F9E820161AE000A88143 /* NSImage+Additions.m in Sources */,
32C0FDE92013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
32F21B5920788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
80377D811F2F66A700F89830 /* enc.c in Sources */,
80377EA71F2F66D400F89830 /* alpha_dec.c in Sources */,
80377D8F1F2F66A700F89830 /* lossless_mips_dsp_r2.c in Sources */,
@ -3767,6 +3794,7 @@
80377CF71F2F66A100F89830 /* enc.c in Sources */,
3237F9EB20161AE000A88143 /* NSImage+Additions.m in Sources */,
32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
80377E871F2F66D000F89830 /* alpha_dec.c in Sources */,
80377D051F2F66A100F89830 /* lossless_mips_dsp_r2.c in Sources */,
80377C0A1F2F665300F89830 /* random_utils.c in Sources */,

View File

@ -199,3 +199,8 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageS
This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class).
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass;
/**
A id<SDWebImageDownloaderRequestModifier> instance to modify the image download request. It's used for downloader to modify the original request from URL and options. If you provide one, it will ignore the `requestModifier` in downloader and use provided one instead. (id<SDWebImageDownloaderRequestModifier>)
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier;

View File

@ -122,3 +122,4 @@ SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager";
SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer";
SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor";
SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass";
SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier";

View File

@ -11,6 +11,7 @@
#import "SDWebImageDefine.h"
#import "SDWebImageOperation.h"
#import "SDWebImageDownloaderConfig.h"
#import "SDWebImageDownloaderRequestModifier.h"
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
/**
@ -81,11 +82,6 @@ typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteg
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished);
typedef NSDictionary<NSString *, NSString *> SDHTTPHeadersDictionary;
typedef NSMutableDictionary<NSString *, NSString *> SDHTTPHeadersMutableDictionary;
typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers);
/**
* A token associated with each download. Can be used to cancel a download
*/
@ -101,6 +97,16 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
*/
@property (nonatomic, strong, nullable, readonly) NSURL *url;
/**
The download's request.
*/
@property (nonatomic, copy, nullable, readonly) NSURLRequest *request;
/**
The download's response.
*/
@property (nonatomic, copy, nullable, readonly) NSURLResponse *response;
@end
@ -116,12 +122,12 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
@property (nonatomic, copy, readonly, nonnull) SDWebImageDownloaderConfig *config;
/**
* Set filter to pick headers for downloading image HTTP request.
*
* This block will be invoked for each downloading image request, returned
* NSDictionary will be used as headers in corresponding HTTP request.
* Set the request modifier to modify the original download request before image load.
* This request modifier method will be called for each downloading image request. Return the original request means no modication. Return nil will cancel the download request.
* Defaults to nil, means does not modify the original download request.
* @note If you want to modify single request, consider using `SDWebImageContextDownloadRequestModifier` context option.
*/
@property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter;
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderRequestModifier> requestModifier;
/**
* The configuration in use by the internal NSURLSession. If you want to provide a custom sessionConfiguration, use `SDWebImageDownloaderConfig.sessionConfiguration` and create a new downloader instance.
@ -188,7 +194,7 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
* before to be called a last time with the full image and finished argument
* set to YES. In case of error, the finished argument is always YES.
*
* @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation
* @return A token (SDWebImageDownloadToken) that can be used to cancel this operation
*/
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
@ -209,7 +215,7 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
* @note the progress block is executed on a background queue
* @param completedBlock A block called once the download is completed.
*
* @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation
* @return A token (SDWebImageDownloadToken) that can be used to cancel this operation
*/
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
@ -217,13 +223,6 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
* Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed:
*
* @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled.
*/
- (void)cancel:(nullable SDWebImageDownloadToken *)token;
/**
* Cancels all download operations in the queue
*/

View File

@ -18,6 +18,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
@interface SDWebImageDownloadToken ()
@property (nonatomic, strong, nullable, readwrite) NSURL *url;
@property (nonatomic, copy, nullable, readwrite) NSURLRequest *request;
@property (nonatomic, copy, nullable, readwrite) NSURLResponse *response;
@property (nonatomic, strong, nullable, readwrite) id downloadOperationCancelToken;
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperation> *downloadOperation;
@property (nonatomic, weak, nullable) SDWebImageDownloader *downloader;
@ -25,15 +27,13 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
@end
@interface SDWebImageDownloader () <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
@property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, NSOperation<SDWebImageDownloaderOperation> *> *URLOperations;
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
@property (copy, atomic, nullable) NSDictionary<NSString *, NSString *> *HTTPHeaders; // Since modify this value is rare, use immutable object can enhance performance. But should mark as atomic to keep thread-safe
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe
@property (strong, nonatomic, nonnull) dispatch_semaphore_t headersLock; // a lock to keep the access to `HTTPHeaders` thread-safe
// The session in which data tasks will run
@property (strong, nonatomic) NSURLSession *session;
@ -91,12 +91,11 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
_downloadQueue.name = @"com.hackemist.SDWebImageDownloader";
_URLOperations = [NSMutableDictionary new];
#ifdef SD_WEBP
_HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy];
_HTTPHeaders = @{@"Accept": @"image/webp,image/*;q=0.8"};
#else
_HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
_HTTPHeaders = @{@"Accept": @"image/*;q=0.8"};
#endif
_operationsLock = dispatch_semaphore_create(1);
_headersLock = dispatch_semaphore_create(1);
NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration;
if (!sessionConfiguration) {
sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
@ -133,27 +132,20 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
}
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field {
LOCK(self.headersLock);
NSMutableDictionary *mutableHTTPHeaders = [self.HTTPHeaders mutableCopy];
if (value) {
self.HTTPHeaders[field] = value;
[mutableHTTPHeaders setObject:value forKey:field];
} else {
[self.HTTPHeaders removeObjectForKey:field];
[mutableHTTPHeaders removeObjectForKey:field];
}
UNLOCK(self.headersLock);
self.HTTPHeaders = [mutableHTTPHeaders copy];
}
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
if (!field) {
return nil;
}
return [[self allHTTPHeaderFields] objectForKey:field];
}
- (nonnull SDHTTPHeadersDictionary *)allHTTPHeaderFields {
LOCK(self.headersLock);
SDHTTPHeadersDictionary *allHTTPHeaderFields = [self.HTTPHeaders copy];
UNLOCK(self.headersLock);
return allHTTPHeaderFields;
return [self.HTTPHeaders objectForKey:field];
}
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock {
@ -176,17 +168,28 @@ 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 *request = [[NSMutableURLRequest alloc] initWithURL:url
cachePolicy:cachePolicy
timeoutInterval:timeoutInterval];
request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
request.HTTPShouldUsePipelining = YES;
if (sself.headersFilter) {
request.allHTTPHeaderFields = sself.headersFilter(url, [sself allHTTPHeaderFields]);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval];
mutableRequest.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
mutableRequest.HTTPShouldUsePipelining = YES;
mutableRequest.allHTTPHeaderFields = sself.HTTPHeaders;
id<SDWebImageDownloaderRequestModifier> requestModifier;
if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) {
requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier];
} else {
requestModifier = self.requestModifier;
}
else {
request.allHTTPHeaderFields = [sself allHTTPHeaderFields];
NSURLRequest *request;
if (requestModifier) {
NSURLRequest *modifiedRequest = [requestModifier modifiedRequestWithRequest:[mutableRequest copy]];
// If modified request is nil, early return
if (!modifiedRequest) {
return nil;
} else {
request = [modifiedRequest copy];
}
} else {
request = [mutableRequest copy];
}
Class operationClass = sself.config.operationClass;
if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperation)]) {
@ -241,8 +244,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
createCallback:(NSOperation<SDWebImageDownloaderOperation> *(^)(void))createCallback {
// The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
if (url == nil) {
if (completedBlock != nil) {
completedBlock(nil, nil, nil, NO);
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to download a nil url"}];
completedBlock(nil, nil, error, YES);
}
return nil;
}
@ -251,6 +255,14 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
if (!operation) {
operation = createCallback();
if (!operation) {
UNLOCK(self.operationsLock);
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}];
completedBlock(nil, nil, error, YES);
}
return nil;
}
__weak typeof(self) wself = self;
operation.completionBlock = ^{
__strong typeof(wself) sself = wself;
@ -273,6 +285,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
SDWebImageDownloadToken *token = [SDWebImageDownloadToken new];
token.downloadOperation = operation;
token.url = url;
token.request = operation.request;
token.downloadOperationCancelToken = downloadOperationCancelToken;
token.downloader = self;
@ -412,6 +425,25 @@ didReceiveResponse:(NSURLResponse *)response
@implementation SDWebImageDownloadToken
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:SDWebImageDownloadReceiveResponseNotification object:nil];
}
- (instancetype)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadReceiveResponse:) name:SDWebImageDownloadReceiveResponseNotification object:nil];
}
return self;
}
- (void)downloadReceiveResponse:(NSNotification *)notification {
NSOperation<SDWebImageDownloaderOperation> *downloadOperation = notification.object;
if (downloadOperation && downloadOperation == self.downloadOperation) {
self.response = downloadOperation.response;
}
}
- (void)cancel {
@synchronized (self) {
if (self.isCancelled) {

View File

@ -93,11 +93,6 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
*/
@property (copy, nonatomic, readonly, nullable) SDWebImageContext *context;
/**
* The expected size of data.
*/
@property (assign, nonatomic, readonly) NSInteger expectedSize;
/**
* Initializes a `SDWebImageDownloaderOperation` object
*

View File

@ -46,7 +46,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
@property (strong, nonatomic, nullable) NSMutableData *imageData;
@property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse`
@property (copy, nonatomic, nullable) NSString *cacheKey;
@property (assign, nonatomic, readwrite) NSInteger expectedSize;
@property (assign, nonatomic, readwrite) long long expectedSize;
@property (strong, nonatomic, nullable, readwrite) NSURLResponse *response;
// This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run

View File

@ -0,0 +1,25 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSURLRequest * _Nonnull request);
@protocol SDWebImageDownloaderRequestModifier <NSObject>
- (nullable NSURLRequest *)modifiedRequestWithRequest:(nonnull NSURLRequest *)request;
@end
@interface SDWebImageDownloaderRequestModifier : NSObject <SDWebImageDownloaderRequestModifier>
- (nonnull instancetype)initWithBlock:(nonnull SDWebImageDownloaderRequestModifierBlock)block;
+ (nonnull instancetype)requestModifierWithBlock:(nonnull SDWebImageDownloaderRequestModifierBlock)block;
@end

View File

@ -0,0 +1,39 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageDownloaderRequestModifier.h"
@interface SDWebImageDownloaderRequestModifier ()
@property (nonatomic, copy, nonnull) SDWebImageDownloaderRequestModifierBlock block;
@end
@implementation SDWebImageDownloaderRequestModifier
- (instancetype)initWithBlock:(SDWebImageDownloaderRequestModifierBlock)block {
self = [super init];
if (self) {
self.block = block;
}
return self;
}
+ (instancetype)requestModifierWithBlock:(SDWebImageDownloaderRequestModifierBlock)block {
SDWebImageDownloaderRequestModifier *requestModifier = [[SDWebImageDownloaderRequestModifier alloc] initWithBlock:block];
return requestModifier;
}
- (NSURLRequest *)modifiedRequestWithRequest:(NSURLRequest *)request {
if (!self.block) {
return nil;
}
return self.block(request);
}
@end

View File

@ -20,6 +20,26 @@ typedef NSString * _Nullable(^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable u
typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL);
// A combined operation representing the cache and download operation. You can it to cancel the load process.
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
/**
Cancel the current operation, including cache and download process
*/
- (void)cancel;
/**
The cache operation used for image cache query
*/
@property (strong, nonatomic, nullable, readonly) id<SDWebImageOperation> cacheOperation;
/**
The download operation if the image is download from the network
*/
@property (strong, nonatomic, nullable, readonly) id<SDWebImageOperation> downloadOperation;
@end
@class SDWebImageManager;
@ -173,12 +193,12 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) {
*
* The last parameter is the original image URL
*
* @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
* @return Returns an instance of SDWebImageCombinedOperation, which you can cancel the loading process.
*/
- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
@ -190,13 +210,13 @@ SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) {
* @note the progress block is executed on a background queue
* @param completedBlock A block called when operation has been completed.
*
* @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation
* @return Returns an instance of SDWebImageCombinedOperation, which you can cancel the loading process.
*/
- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
/**
* Saves image to cache for given URL

View File

@ -11,11 +11,11 @@
#import "UIImage+WebCache.h"
#import "SDAnimatedImage.h"
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
@interface SDWebImageCombinedOperation ()
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (strong, nonatomic, nullable) SDWebImageDownloadToken *downloadToken;
@property (strong, nonatomic, nullable) NSOperation *cacheOperation;
@property (strong, nonatomic, readwrite, nullable) id<SDWebImageOperation> downloadOperation;
@property (strong, nonatomic, readwrite, nullable) id<SDWebImageOperation> cacheOperation;
@property (weak, nonatomic, nullable) SDWebImageManager *manager;
@end
@ -108,15 +108,15 @@
}];
}
- (id<SDWebImageOperation>)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock {
- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock {
return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock];
}
- (id<SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock {
- (SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock {
// Invoking this method without a completedBlock is pointless
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
@ -216,7 +216,7 @@
// `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle
__weak typeof(strongOperation) weakSubOperation = strongOperation;
strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) {
strongOperation.downloadOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions context:context progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) {
__strong typeof(weakSubOperation) strongSubOperation = weakSubOperation;
if (!strongSubOperation || strongSubOperation.isCancelled) {
// Do nothing if the operation was cancelled
@ -372,13 +372,17 @@
- (void)cancel {
@synchronized(self) {
if (self.isCancelled) {
return;
}
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.downloadToken) {
[self.manager.imageDownloader cancel:self.downloadToken];
if (self.downloadOperation) {
[self.downloadOperation cancel];
self.downloadOperation = nil;
}
[self.manager safelyRemoveOperationFromRunning:self];
}

View File

@ -16,6 +16,14 @@
// All the stored operations are weak, so it will be dalloced after image loading finished. If you need to store operations, use your own class to keep a strong reference for them.
@interface UIView (WebCacheOperation)
/**
* Get the image load operation for key
*
* @param key key for identifying the operations
* @return the image load operation
*/
- (nullable id<SDWebImageOperation>)sd_imageLoadOperationForKey:(nullable NSString *)key;
/**
* Set the image load operation (storage in a UIView based weak map table)
*

View File

@ -32,6 +32,15 @@ typedef NSMapTable<NSString *, id<SDWebImageOperation>> SDOperationsDictionary;
}
}
- (nullable id<SDWebImageOperation>)sd_imageLoadOperationForKey:(nullable NSString *)key {
id<SDWebImageOperation> operation;
SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
@synchronized (self) {
operation = [operationDictionary objectForKey:key];
}
return operation;
}
- (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key {
if (key) {
[self sd_cancelImageLoadOperationWithKey:key];

View File

@ -109,10 +109,10 @@
- (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils {
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with nils"];
[[SDWebImageDownloader sharedDownloader] addProgressCallback:nil completedBlock:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
if (!image && !data && !error) {
if (!image && !data && error) {
[expectation fulfill];
} else {
XCTFail(@"All params should be nil");
XCTFail(@"All params except error should be nil");
}
} forURL:nil createCallback:nil];
[self waitForExpectationsWithTimeout:0.5 handler:nil];
@ -174,7 +174,7 @@
}];
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
[[SDWebImageDownloader sharedDownloader] cancel:token];
[token cancel];
// doesn't cancel immediately - since it uses dispatch async
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{
@ -298,7 +298,7 @@
}];
expect(token2).toNot.beNil();
[[SDWebImageDownloader sharedDownloader] cancel:token1];
[token1 cancel];
[self waitForExpectationsWithCommonTimeout];
}
@ -323,7 +323,7 @@
}];
expect(token1).toNot.beNil();
[[SDWebImageDownloader sharedDownloader] cancel:token1];
[token1 cancel];
SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader]
downloadImageWithURL:imageURL
@ -369,4 +369,49 @@
}
#endif
- (void)test23ThatDownloadRequestModifierWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"Download request modifier not works"];
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init];
SDWebImageDownloaderRequestModifier *requestModifier = [SDWebImageDownloaderRequestModifier requestModifierWithBlock:^NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) {
if ([request.URL.absoluteString isEqualToString:kTestPNGURL]) {
// Test that return a modified request
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest setValue:@"Bar" forHTTPHeaderField:@"Foo"];
NSURLComponents *components = [NSURLComponents componentsWithURL:mutableRequest.URL resolvingAgainstBaseURL:NO];
components.query = @"text=Hello+World";
mutableRequest.URL = components.URL;
return mutableRequest;
} else if ([request.URL.absoluteString isEqualToString:kTestJpegURL]) {
// Test that return nil request will treat as error
return nil;
} else {
return request;
}
}];
downloader.requestModifier = requestModifier;
__block BOOL firstCheck = NO;
__block BOOL secondCheck = NO;
[downloader downloadImageWithURL:[NSURL URLWithString:kTestJpegURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
// Except error
expect(error).notTo.beNil();
firstCheck = YES;
if (firstCheck && secondCheck) {
[expectation fulfill];
}
}];
[downloader downloadImageWithURL:[NSURL URLWithString:kTestPNGURL] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
// Expect not error
expect(error).to.beNil();
secondCheck = YES;
if (firstCheck && secondCheck) {
[expectation fulfill];
}
}];
[self waitForExpectationsWithCommonTimeout];
}
@end

View File

@ -29,6 +29,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#import <SDWebImage/UIImageView+HighlightedWebCache.h>
#import <SDWebImage/SDWebImageDownloaderConfig.h>
#import <SDWebImage/SDWebImageDownloaderOperation.h>
#import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
#import <SDWebImage/UIButton+WebCache.h>
#import <SDWebImage/SDWebImagePrefetcher.h>
#import <SDWebImage/UIView+WebCacheOperation.h>