You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ensure the DownloaderOperation callback the completion in atomic and never miss one
The downloader will now check and ignore a `transferedDataFinished` operation (which is callbacking its own completion), because it's not safe in multi-thread environment, create new network request instead
/// Whether the operation's network data transfer is finished. This is used by downloader to decide whether to call `addHandlersForProgress:`, or create a new operation instead.
62
+
/// @note You must implements this or this will cause downloader attach new handlers for a already finished operation, may cause some callback missing.
@property (strong, nonatomic, nonnull) NSOperationQueue *coderQueue; // the serial operation queue to do image decoding
76
+
@property (strong, nonatomic, nonnull) dispatch_queue_t coderQueue; // the serial operation queue to do image decoding
77
+
@property (assign, readwrite) BOOL isTransferFinished; // Whether current operation's network transfer is finished (actually, `didCompleteWithError` already been called)
77
78
78
79
@property (strong, nonatomic, nonnull) NSMapTable<SDImageCoderOptions *, UIImage *> *imageMap; // each variant of image is weak-referenced to avoid too many re-decode during downloading
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, NO, self, [[selfclass] imageOptionsFromDownloaderOptions:self.options], self.context);
480
-
if (self.isFinished) {
481
-
return;
482
-
}
483
-
if (image) {
484
-
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
// When cancelled or transfer finished (`didCompleteWithError`), cancel the progress callback, only completed block is called and enough
475
+
if (self.isCancelled || self.isTransferFinished) {
476
+
return;
477
+
}
478
+
UIImage *image = SDImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, NO, self, [[selfclass] imageOptionsFromDownloaderOptions:self.options], self.context);
479
+
if (image) {
480
+
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
// call [self done] after all completed block was dispatched
619
-
[self.coderQueue addOperation:doneOperation];
602
+
dispatch_barrier_async(self.coderQueue, ^{
603
+
@strongify(self);
604
+
if (!self) {
605
+
return;
606
+
}
607
+
[selfdone];
608
+
});
609
+
dispatch_async(self.coderQueue, ^{
610
+
[selfdone];
611
+
});
620
612
}
621
613
} else {
622
614
[selfcallCompletionBlocksWithError:[NSErrorerrorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorBadImageData userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]];
0 commit comments