Selaa lähdekoodia

Merge pull request #3403 from dreampiggy/revert_isCancelled_block_with_recursive

Fix the crash because of SDWebImageCombinedOperation recursive lock
DreamPiggy 3 vuotta sitten
vanhempi
sitoutus
524d4f53eb
2 muutettua tiedostoa jossa 23 lisäystä ja 31 poistoa
  1. 3 0
      SDWebImage/Core/SDWebImageManager.h
  2. 20 31
      SDWebImage/Core/SDWebImageManager.m

+ 3 - 0
SDWebImage/Core/SDWebImageManager.h

@@ -29,6 +29,9 @@ typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nu
  */
 - (void)cancel;
 
+/// Whether the operation has been cancelled.
+@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
+
 /**
  The cache operation from the image cache query
  */

+ 20 - 31
SDWebImage/Core/SDWebImageManager.m

@@ -17,9 +17,7 @@
 static id<SDImageCache> _defaultImageCache;
 static id<SDImageLoader> _defaultImageLoader;
 
-@interface SDWebImageCombinedOperation () {
-    SD_LOCK_DECLARE(_cancelledLock); // a lock to keep the access to `cancelled` thread-safe
-}
+@interface SDWebImageCombinedOperation ()
 
 @property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
 @property (strong, nonatomic, readwrite, nullable) id<SDWebImageOperation> loaderOperation;
@@ -805,39 +803,30 @@ static id<SDImageLoader> _defaultImageLoader;
 
 @implementation SDWebImageCombinedOperation
 
-- (instancetype)init {
-    if (self = [super init]) {
-        SD_LOCK_INIT(_cancelledLock);
-    }
-
-    return self;
-}
-
 - (BOOL)isCancelled {
-    BOOL isCancelled = NO;
-    SD_LOCK(_cancelledLock);
-    isCancelled = _cancelled;
-    SD_UNLOCK(_cancelledLock);
-    return isCancelled;
+    // Need recursive lock (user's cancel block may check isCancelled), do not use SD_LOCK
+    @synchronized (self) {
+        return _cancelled;
+    }
 }
 
 - (void)cancel {
-    SD_LOCK(_cancelledLock);
-    if (_cancelled) {
-        SD_UNLOCK(_cancelledLock);
-        return;
-    }
-    _cancelled = YES;
-    if (self.cacheOperation) {
-        [self.cacheOperation cancel];
-        self.cacheOperation = nil;
-    }
-    if (self.loaderOperation) {
-        [self.loaderOperation cancel];
-        self.loaderOperation = nil;
+    // Need recursive lock (user's cancel block may check isCancelled), do not use SD_LOCK
+    @synchronized(self) {
+        if (_cancelled) {
+            return;
+        }
+        _cancelled = YES;
+        if (self.cacheOperation) {
+            [self.cacheOperation cancel];
+            self.cacheOperation = nil;
+        }
+        if (self.loaderOperation) {
+            [self.loaderOperation cancel];
+            self.loaderOperation = nil;
+        }
+        [self.manager safelyRemoveOperationFromRunning:self];
     }
-    [self.manager safelyRemoveOperationFromRunning:self];
-    SD_UNLOCK(_cancelledLock);
 }
 
 @end