Decode the image in the operation level's queue instead of URLSession delegate q…
…ueue. Because URLSession delegate queue is a barrier queue and shared between different operations
Showing
1 changed file
with
18 additions
and
5 deletions
@@ -38,7 +38,9 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; | @@ -38,7 +38,9 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; | ||
38 | 38 | ||
39 | @property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask; | 39 | @property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask; |
40 | 40 | ||
41 | -@property (strong, nonatomic, nullable) dispatch_queue_t barrierQueue; | 41 | +@property (strong, nonatomic, nonnull) dispatch_queue_t barrierQueue; |
42 | + | ||
43 | +@property (strong, nonatomic, nonnull) dispatch_queue_t coderQueue; | ||
42 | 44 | ||
43 | #if SD_UIKIT | 45 | #if SD_UIKIT |
44 | @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; | 46 | @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; |
@@ -70,6 +72,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; | @@ -70,6 +72,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; | ||
70 | _expectedSize = 0; | 72 | _expectedSize = 0; |
71 | _unownedSession = session; | 73 | _unownedSession = session; |
72 | _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationBarrierQueue", DISPATCH_QUEUE_CONCURRENT); | 74 | _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationBarrierQueue", DISPATCH_QUEUE_CONCURRENT); |
75 | + _coderQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationCoderQueue", DISPATCH_QUEUE_SERIAL); | ||
73 | } | 76 | } |
74 | return self; | 77 | return self; |
75 | } | 78 | } |
@@ -316,7 +319,7 @@ didReceiveResponse:(NSURLResponse *)response | @@ -316,7 +319,7 @@ didReceiveResponse:(NSURLResponse *)response | ||
316 | 319 | ||
317 | if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { | 320 | if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { |
318 | // Get the image data | 321 | // Get the image data |
319 | - NSData *imageData = [self.imageData copy]; | 322 | + __block NSData *imageData = [self.imageData copy]; |
320 | // Get the total bytes downloaded | 323 | // Get the total bytes downloaded |
321 | const NSInteger totalSize = imageData.length; | 324 | const NSInteger totalSize = imageData.length; |
322 | // Get the finish status | 325 | // Get the finish status |
@@ -333,16 +336,18 @@ didReceiveResponse:(NSURLResponse *)response | @@ -333,16 +336,18 @@ didReceiveResponse:(NSURLResponse *)response | ||
333 | } | 336 | } |
334 | } | 337 | } |
335 | 338 | ||
339 | + dispatch_async(self.coderQueue, ^{ | ||
336 | UIImage *image = [self.progressiveCoder incrementallyDecodedImageWithData:imageData finished:finished]; | 340 | UIImage *image = [self.progressiveCoder incrementallyDecodedImageWithData:imageData finished:finished]; |
337 | if (image) { | 341 | if (image) { |
338 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; | 342 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; |
339 | image = [self scaledImageForKey:key image:image]; | 343 | image = [self scaledImageForKey:key image:image]; |
340 | if (self.shouldDecompressImages) { | 344 | if (self.shouldDecompressImages) { |
341 | - image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&data options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; | 345 | + image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; |
342 | } | 346 | } |
343 | 347 | ||
344 | [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; | 348 | [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; |
345 | } | 349 | } |
350 | + }); | ||
346 | } | 351 | } |
347 | 352 | ||
348 | for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { | 353 | for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { |
@@ -380,14 +385,16 @@ didReceiveResponse:(NSURLResponse *)response | @@ -380,14 +385,16 @@ didReceiveResponse:(NSURLResponse *)response | ||
380 | }); | 385 | }); |
381 | } | 386 | } |
382 | 387 | ||
388 | + // make sure to call `[self done]` to mark operation as finished | ||
383 | if (error) { | 389 | if (error) { |
384 | [self callCompletionBlocksWithError:error]; | 390 | [self callCompletionBlocksWithError:error]; |
391 | + [self done]; | ||
385 | } else { | 392 | } else { |
386 | if ([self callbacksForKey:kCompletedCallbackKey].count > 0) { | 393 | if ([self callbacksForKey:kCompletedCallbackKey].count > 0) { |
387 | /** | 394 | /** |
388 | * If you specified to use `NSURLCache`, then the response you get here is what you need. | 395 | * If you specified to use `NSURLCache`, then the response you get here is what you need. |
389 | */ | 396 | */ |
390 | - NSData *imageData = [self.imageData copy]; | 397 | + __block NSData *imageData = [self.imageData copy]; |
391 | if (imageData) { | 398 | if (imageData) { |
392 | /** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`, | 399 | /** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`, |
393 | * then we should check if the cached data is equal to image data | 400 | * then we should check if the cached data is equal to image data |
@@ -395,7 +402,9 @@ didReceiveResponse:(NSURLResponse *)response | @@ -395,7 +402,9 @@ didReceiveResponse:(NSURLResponse *)response | ||
395 | if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) { | 402 | if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) { |
396 | // call completion block with nil | 403 | // call completion block with nil |
397 | [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES]; | 404 | [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES]; |
405 | + [self done]; | ||
398 | } else { | 406 | } else { |
407 | + dispatch_async(self.coderQueue, ^{ | ||
399 | UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:imageData]; | 408 | UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:imageData]; |
400 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; | 409 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; |
401 | image = [self scaledImageForKey:key image:image]; | 410 | image = [self scaledImageForKey:key image:image]; |
@@ -425,13 +434,17 @@ didReceiveResponse:(NSURLResponse *)response | @@ -425,13 +434,17 @@ didReceiveResponse:(NSURLResponse *)response | ||
425 | } else { | 434 | } else { |
426 | [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; | 435 | [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; |
427 | } | 436 | } |
437 | + [self done]; | ||
438 | + }); | ||
428 | } | 439 | } |
429 | } else { | 440 | } else { |
430 | [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; | 441 | [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; |
442 | + [self done]; | ||
431 | } | 443 | } |
444 | + } else { | ||
445 | + [self done]; | ||
432 | } | 446 | } |
433 | } | 447 | } |
434 | - [self done]; | ||
435 | } | 448 | } |
436 | 449 | ||
437 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { | 450 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { |
-
Please register or login to post a comment