Authored by 朱小军

提交图片下载失败,走下发IP直连重试功能 review 小熊

@@ -68,15 +68,24 @@ extern NSString *const SDWebImageDownloadStopNotification; @@ -68,15 +68,24 @@ extern NSString *const SDWebImageDownloadStopNotification;
68 68
69 typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); 69 typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);
70 70
71 -typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished); 71 +typedef void(^SDWebImageDownloaderCompletedBlock)(NSURLRequest *request,UIImage *image, NSData *data, NSError *error, BOOL finished);
72 72
73 typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDictionary *headers); 73 typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDictionary *headers);
74 74
  75 +@protocol SDWebImageDownloaderDelegate <NSObject>
  76 +
  77 +@optional
  78 +/**
  79 + * 走图片下载直连ip请求时设置超时时间为5s.
  80 + */
  81 +- (NSTimeInterval)setDirectIpRetryTimeout:(NSString *)host;
  82 +@end
75 /** 83 /**
76 * Asynchronous downloader dedicated and optimized for image loading. 84 * Asynchronous downloader dedicated and optimized for image loading.
77 */ 85 */
78 @interface SDWebImageDownloader : NSObject 86 @interface SDWebImageDownloader : NSObject
79 87
  88 +@property (weak, nonatomic) id <SDWebImageDownloaderDelegate> delegate;
80 /** 89 /**
81 * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. 90 * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory.
82 * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. 91 * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
@@ -118,6 +118,11 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -118,6 +118,11 @@ static NSString *const kCompletedCallbackKey = @"completed";
118 118
119 [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{ 119 [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{
120 NSTimeInterval timeoutInterval = wself.downloadTimeout; 120 NSTimeInterval timeoutInterval = wself.downloadTimeout;
  121 +
  122 + if ([self.delegate respondsToSelector:@selector(setDirectIpRetryTimeout:)]) {
  123 + timeoutInterval = [self.delegate setDirectIpRetryTimeout:url.host];
  124 + }
  125 +
121 if (timeoutInterval == 0.0) { 126 if (timeoutInterval == 0.0) {
122 timeoutInterval = 15.0; 127 timeoutInterval = 15.0;
123 } 128 }
@@ -146,9 +151,10 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -146,9 +151,10 @@ static NSString *const kCompletedCallbackKey = @"completed";
146 if (callback) callback(receivedSize, expectedSize); 151 if (callback) callback(receivedSize, expectedSize);
147 } 152 }
148 } 153 }
149 - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { 154 + completed:^(NSURLRequest *requestx,UIImage *image, NSData *data, NSError *error, BOOL finished) {
150 SDWebImageDownloader *sself = wself; 155 SDWebImageDownloader *sself = wself;
151 if (!sself) return; 156 if (!sself) return;
  157 +
152 __block NSArray *callbacksForURL; 158 __block NSArray *callbacksForURL;
153 dispatch_barrier_sync(sself.barrierQueue, ^{ 159 dispatch_barrier_sync(sself.barrierQueue, ^{
154 callbacksForURL = [sself.URLCallbacks[url] copy]; 160 callbacksForURL = [sself.URLCallbacks[url] copy];
@@ -158,12 +164,13 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -158,12 +164,13 @@ static NSString *const kCompletedCallbackKey = @"completed";
158 }); 164 });
159 for (NSDictionary *callbacks in callbacksForURL) { 165 for (NSDictionary *callbacks in callbacksForURL) {
160 SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey]; 166 SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];
161 - if (callback) callback(image, data, error, finished); 167 + if (callback) callback(requestx, image, data, error, finished);
162 } 168 }
163 } 169 }
164 cancelled:^{ 170 cancelled:^{
165 SDWebImageDownloader *sself = wself; 171 SDWebImageDownloader *sself = wself;
166 if (!sself) return; 172 if (!sself) return;
  173 +
167 dispatch_barrier_async(sself.barrierQueue, ^{ 174 dispatch_barrier_async(sself.barrierQueue, ^{
168 [sself.URLCallbacks removeObjectForKey:url]; 175 [sself.URLCallbacks removeObjectForKey:url];
169 }); 176 });
@@ -195,7 +202,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; @@ -195,7 +202,7 @@ static NSString *const kCompletedCallbackKey = @"completed";
195 // 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. 202 // 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.
196 if (url == nil) { 203 if (url == nil) {
197 if (completedBlock != nil) { 204 if (completedBlock != nil) {
198 - completedBlock(nil, nil, nil, NO); 205 + completedBlock(nil,nil, nil, nil, NO);
199 } 206 }
200 return; 207 return;
201 } 208 }
@@ -125,7 +125,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -125,7 +125,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
125 } 125 }
126 else { 126 else {
127 if (self.completedBlock) { 127 if (self.completedBlock) {
128 - self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES); 128 + self.completedBlock(nil, nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES);
129 } 129 }
130 } 130 }
131 131
@@ -264,7 +264,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -264,7 +264,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
264 }); 264 });
265 265
266 if (self.completedBlock) { 266 if (self.completedBlock) {
267 - self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES); 267 + self.completedBlock(nil, nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
268 } 268 }
269 CFRunLoopStop(CFRunLoopGetCurrent()); 269 CFRunLoopStop(CFRunLoopGetCurrent());
270 [self done]; 270 [self done];
@@ -342,7 +342,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -342,7 +342,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
342 CGImageRelease(partialImageRef); 342 CGImageRelease(partialImageRef);
343 dispatch_main_sync_safe(^{ 343 dispatch_main_sync_safe(^{
344 if (self.completedBlock) { 344 if (self.completedBlock) {
345 - self.completedBlock(image, nil, nil, NO); 345 + self.completedBlock(nil, image, nil, nil, NO);
346 } 346 }
347 }); 347 });
348 } 348 }
@@ -401,7 +401,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -401,7 +401,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
401 401
402 if (completionBlock) { 402 if (completionBlock) {
403 if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) { 403 if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) {
404 - completionBlock(nil, nil, nil, YES); 404 + completionBlock(nil, nil, nil, nil, YES);
405 } else if (self.imageData) { 405 } else if (self.imageData) {
406 UIImage *image = [UIImage sd_imageWithData:self.imageData]; 406 UIImage *image = [UIImage sd_imageWithData:self.imageData];
407 NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; 407 NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
@@ -414,13 +414,13 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -414,13 +414,13 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
414 } 414 }
415 } 415 }
416 if (CGSizeEqualToSize(image.size, CGSizeZero)) { 416 if (CGSizeEqualToSize(image.size, CGSizeZero)) {
417 - completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES); 417 + completionBlock(nil, nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES);
418 } 418 }
419 else { 419 else {
420 - completionBlock(image, self.imageData, nil, YES); 420 + completionBlock(self.request, image, self.imageData, nil, YES);
421 } 421 }
422 } else { 422 } else {
423 - completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}], YES); 423 + completionBlock(nil, nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}], YES);
424 } 424 }
425 } 425 }
426 self.completionBlock = nil; 426 self.completionBlock = nil;
@@ -439,7 +439,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis @@ -439,7 +439,7 @@ NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinis
439 } 439 }
440 440
441 if (self.completedBlock) { 441 if (self.completedBlock) {
442 - self.completedBlock(nil, nil, error, YES); 442 + self.completedBlock(nil, nil, nil, error, YES);
443 } 443 }
444 self.completionBlock = nil; 444 self.completionBlock = nil;
445 [self done]; 445 [self done];
@@ -113,8 +113,31 @@ typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url); @@ -113,8 +113,31 @@ typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
113 * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied. 113 * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
114 */ 114 */
115 - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL; 115 - (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
  116 +/**
  117 + * If download image from original url failed,app use img_ip retry again
  118 + *
  119 + * @param imageManager The current `SDWebImageManager`
  120 + * @param imageURL The url of the image to be downloaded
  121 + * @param options SDWebImageOptions
  122 +* @param progressBlock progressBlock
  123 +* @param completedBlock completedBlock
  124 + * @return NONE.
  125 + */
  126 +- (void)imageManager:(SDWebImageManager *)imageManager didFailedDownloadImageWithURL:(NSURL *)imageURL
  127 + options:(SDWebImageOptions)options
  128 + progress:(SDWebImageDownloaderProgressBlock)progressBlock
  129 + completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
116 130
117 /** 131 /**
  132 + * Controls which image should be downloaded when the image is not found in the cache.
  133 + *
  134 + * @param imageManager The current `SDWebImageManager`
  135 + * @param imageURL The url of the image to be downloaded
  136 + *
  137 + * @return Return original url
  138 + */
  139 +- (NSString *)imageManager:(SDWebImageManager *)imageManager didSuccessedWithRequest:(NSURLRequest *)request cacheKey:(NSString *)key;
  140 +/**
118 * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory. 141 * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
119 * NOTE: This method is called from a global queue in order to not to block the main thread. 142 * NOTE: This method is called from a global queue in order to not to block the main thread.
120 * 143 *
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 8
9 #import "SDWebImageManager.h" 9 #import "SDWebImageManager.h"
10 #import <objc/message.h> 10 #import <objc/message.h>
  11 +#import "SDWebImageDownloaderOperation.h"
11 12
12 @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation> 13 @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
13 14
@@ -144,7 +145,7 @@ @@ -144,7 +145,7 @@
144 @synchronized (self.runningOperations) { 145 @synchronized (self.runningOperations) {
145 [self.runningOperations addObject:operation]; 146 [self.runningOperations addObject:operation];
146 } 147 }
147 - NSString *key = [self cacheKeyForURL:url]; 148 + __block NSString *key = [self cacheKeyForURL:url];
148 149
149 operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) { 150 operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
150 if (operation.isCancelled) { 151 if (operation.isCancelled) {
@@ -179,7 +180,8 @@ @@ -179,7 +180,8 @@
179 // ignore image read from NSURLCache if image if cached but force refreshing 180 // ignore image read from NSURLCache if image if cached but force refreshing
180 downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; 181 downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
181 } 182 }
182 - id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) { 183 + id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(NSURLRequest *request,UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
  184 +
183 if (weakOperation.isCancelled) { 185 if (weakOperation.isCancelled) {
184 // Do nothing if the operation was cancelled 186 // Do nothing if the operation was cancelled
185 // See #699 for more details 187 // See #699 for more details
@@ -188,19 +190,32 @@ @@ -188,19 +190,32 @@
188 else if (error) { 190 else if (error) {
189 dispatch_main_sync_safe(^{ 191 dispatch_main_sync_safe(^{
190 if (!weakOperation.isCancelled) { 192 if (!weakOperation.isCancelled) {
191 - completedBlock(nil, error, SDImageCacheTypeNone, finished, url); 193 + completedBlock( nil, error, SDImageCacheTypeNone, finished, url);
192 } 194 }
193 }); 195 });
194 196
195 BOOL shouldBeFailedURLAlliOSVersion = (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut); 197 BOOL shouldBeFailedURLAlliOSVersion = (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut);
196 BOOL shouldBeFailedURLiOS7 = (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1 && error.code != NSURLErrorInternationalRoamingOff && error.code != NSURLErrorCallIsActive && error.code != NSURLErrorDataNotAllowed); 198 BOOL shouldBeFailedURLiOS7 = (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1 && error.code != NSURLErrorInternationalRoamingOff && error.code != NSURLErrorCallIsActive && error.code != NSURLErrorDataNotAllowed);
197 if (shouldBeFailedURLAlliOSVersion || shouldBeFailedURLiOS7) { 199 if (shouldBeFailedURLAlliOSVersion || shouldBeFailedURLiOS7) {
  200 +
  201 + if ([self.delegate respondsToSelector:@selector(imageManager:didFailedDownloadImageWithURL:options:progress:completed:)]) {
  202 + [self.delegate imageManager:self didFailedDownloadImageWithURL:url options:options progress:progressBlock completed:completedBlock];
  203 + }
  204 +
198 @synchronized (self.failedURLs) { 205 @synchronized (self.failedURLs) {
199 [self.failedURLs addObject:url]; 206 [self.failedURLs addObject:url];
200 } 207 }
201 } 208 }
202 } 209 }
203 else { 210 else {
  211 +
  212 + if ([self.delegate respondsToSelector:@selector(imageManager:didSuccessedWithRequest:cacheKey:)]){
  213 + NSString * originalUrl = [self.delegate imageManager:self didSuccessedWithRequest:request cacheKey:key];
  214 + if (originalUrl.length > 0) {
  215 + key = originalUrl;
  216 + }
  217 + }
  218 +
204 if ((options & SDWebImageRetryFailed)) { 219 if ((options & SDWebImageRetryFailed)) {
205 @synchronized (self.failedURLs) { 220 @synchronized (self.failedURLs) {
206 [self.failedURLs removeObject:url]; 221 [self.failedURLs removeObject:url];