Răsfoiți Sursa

Merge branch '5.7.x' of https://github.com/SDWebImage/SDWebImage

# Conflicts:
#	SDWebImage.xcodeproj/project.pbxproj
DreamPiggy 5 ani în urmă
părinte
comite
7a430b23b9

+ 6 - 0
CHANGELOG.md

@@ -1,3 +1,9 @@
+## [5.7.4 - 5.7 Patch, on May 6th, 2020](https://github.com/SDWebImage/SDWebImage/releases/tag/5.7.4)
+See [all tickets marked for the 5.7.4 release](https://github.com/SDWebImage/SDWebImage/milestone/71)
+
+### Fixes
+- Fix the issue that NSOperation conforms to `SDWebImageOperation` check failed. Fix cancelling prefetcher hung up #2999 #2998
+
 ## [5.7.3 - 5.7 Patch, on Apr 21st, 2020](https://github.com/SDWebImage/SDWebImage/releases/tag/5.7.3)
 See [all tickets marked for the 5.7.3 release](https://github.com/SDWebImage/SDWebImage/milestone/70)
 

+ 1 - 1
SDWebImage.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name = 'SDWebImage'
-  s.version = '5.7.3'
+  s.version = '5.7.4'
 
   s.osx.deployment_target = '10.10'
   s.ios.deployment_target = '8.0'

+ 6 - 0
SDWebImage.xcodeproj/project.pbxproj

@@ -115,6 +115,8 @@
 		327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */; };
 		3287E6D1244C0C1400007311 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3287E6CD244C0C1400007311 /* MKAnnotationView+WebCache.m */; };
 		3287E6D2244C0C1400007311 /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 3287E6CE244C0C1400007311 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		327F2E83245AE1650075F846 /* SDWebImageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 327F2E82245AE1650075F846 /* SDWebImageOperation.m */; };
+		327F2E84245AE1650075F846 /* SDWebImageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 327F2E82245AE1650075F846 /* SDWebImageOperation.m */; };
 		328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; };
 		328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */; };
@@ -441,6 +443,7 @@
 		327054D3206CD8B3006EA328 /* SDImageAPNGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDImageAPNGCoder.m; path = Core/SDImageAPNGCoder.m; sourceTree = "<group>"; };
 		3287E6CD244C0C1400007311 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = "<group>"; };
 		3287E6CE244C0C1400007311 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = "<group>"; };
+		327F2E82245AE1650075F846 /* SDWebImageOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageOperation.m; path = Core/SDWebImageOperation.m; sourceTree = "<group>"; };
 		328BB69A2081FED200760D6C /* SDWebImageCacheKeyFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageCacheKeyFilter.h; path = Core/SDWebImageCacheKeyFilter.h; sourceTree = "<group>"; };
 		328BB69B2081FED200760D6C /* SDWebImageCacheKeyFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCacheKeyFilter.m; path = Core/SDWebImageCacheKeyFilter.m; sourceTree = "<group>"; };
 		328BB6A82081FEE500760D6C /* SDWebImageCacheSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageCacheSerializer.h; path = Core/SDWebImageCacheSerializer.h; sourceTree = "<group>"; };
@@ -857,6 +860,7 @@
 				320CAE132086F50500CFFC80 /* SDWebImageError.h */,
 				320CAE142086F50500CFFC80 /* SDWebImageError.m */,
 				530E49E71646388E002868E7 /* SDWebImageOperation.h */,
+				327F2E82245AE1650075F846 /* SDWebImageOperation.m */,
 				324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */,
 				324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */,
 				325312C6200F09910046BF1E /* SDWebImageTransition.h */,
@@ -1208,6 +1212,7 @@
 				4A2CAE201AB4BB6C00B6BC39 /* SDImageCache.m in Sources */,
 				4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */,
 				329A18611FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */,
+				327F2E84245AE1650075F846 /* SDWebImageOperation.m in Sources */,
 				328BB6B22081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */,
 				325C4611223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */,
 			);
@@ -1282,6 +1287,7 @@
 				ABBE71A818C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m in Sources */,
 				4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */,
 				329A185F1FFF5DFD008C9A2F /* UIImage+Metadata.m in Sources */,
+				327F2E83245AE1650075F846 /* SDWebImageOperation.m in Sources */,
 				328BB6B02081FEE500760D6C /* SDWebImageCacheSerializer.m in Sources */,
 				325C4610223394D8004CAE11 /* SDImageCachesManagerOperation.m in Sources */,
 			);

+ 14 - 0
SDWebImage/Core/SDWebImageOperation.m

@@ -0,0 +1,14 @@
+/*
+ * 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 "SDWebImageOperation.h"
+
+/// NSOperation conform to `SDWebImageOperation`.
+@implementation NSOperation (SDWebImageOperation)
+
+@end

+ 38 - 21
SDWebImage/Core/SDWebImagePrefetcher.m

@@ -20,6 +20,10 @@
     atomic_flag  _isAllFinished;
     
     unsigned long _totalCount;
+    
+    // Used to ensure NSPointerArray thread safe
+    dispatch_semaphore_t _prefetchOperationsLock;
+    dispatch_semaphore_t _loadOperationsLock;
 }
 
 @property (nonatomic, copy, readwrite) NSArray<NSURL *> *urls;
@@ -106,7 +110,6 @@
 }
 
 - (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token {
-    NSPointerArray *operations = token.loadOperations;
     for (NSURL *url in token.urls) {
         @autoreleasepool {
             @weakify(self);
@@ -142,13 +145,13 @@
                     [asyncOperation complete];
                 }];
                 NSAssert(operation != nil, @"Operation should not be nil, [SDWebImageManager loadImageWithURL:options:context:progress:completed:] break prefetch logic");
-                @synchronized (token) {
-                    [operations addPointer:(__bridge void *)operation];
-                }
+                SD_LOCK(token->_loadOperationsLock);
+                [token.loadOperations addPointer:(__bridge void *)operation];
+                SD_UNLOCK(token->_loadOperationsLock);
             }];
-            @synchronized (token) {
-                [token.prefetchOperations addPointer:(__bridge void *)prefetchOperation];
-            }
+            SD_LOCK(token->_prefetchOperationsLock);
+            [token.prefetchOperations addPointer:(__bridge void *)prefetchOperation];
+            SD_UNLOCK(token->_prefetchOperationsLock);
             [self.prefetchQueue addOperation:prefetchOperation];
         }
     }
@@ -262,24 +265,38 @@
 
 @implementation SDWebImagePrefetchToken
 
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        _prefetchOperationsLock = dispatch_semaphore_create(1);
+        _loadOperationsLock = dispatch_semaphore_create(1);
+    }
+    return self;
+}
+
 - (void)cancel {
-    @synchronized (self) {
-        [self.prefetchOperations compact];
-        for (id operation in self.prefetchOperations) {
-            if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
-                [operation cancel];
-            }
+    SD_LOCK(_prefetchOperationsLock);
+    [self.prefetchOperations compact];
+    for (id operation in self.prefetchOperations) {
+        id<SDWebImageOperation> strongOperation = operation;
+        if (strongOperation) {
+            [strongOperation cancel];
         }
-        self.prefetchOperations.count = 0;
-        
-        [self.loadOperations compact];
-        for (id operation in self.loadOperations) {
-            if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
-                [operation cancel];
-            }
+    }
+    self.prefetchOperations.count = 0;
+    SD_UNLOCK(_prefetchOperationsLock);
+    
+    SD_LOCK(_loadOperationsLock);
+    [self.loadOperations compact];
+    for (id operation in self.loadOperations) {
+        id<SDWebImageOperation> strongOperation = operation;
+        if (strongOperation) {
+            [strongOperation cancel];
         }
-        self.loadOperations.count = 0;
     }
+    self.loadOperations.count = 0;
+    SD_UNLOCK(_loadOperationsLock);
+    
     self.completionBlock = nil;
     self.progressBlock = nil;
     [self.prefetcher removeRunningToken:self];

+ 43 - 18
SDWebImage/Private/SDAsyncBlockOperation.m

@@ -35,33 +35,58 @@
 }
 
 - (void)start {
-    if (self.isCancelled) {
-        return;
-    }
-    
-    [self willChangeValueForKey:@"isExecuting"];
-    self.executing = YES;
-    [self didChangeValueForKey:@"isExecuting"];
-    
-    if (self.executionBlock) {
-        self.executionBlock(self);
-    } else {
-        [self complete];
+    @synchronized (self) {
+        if (self.isCancelled) {
+            self.finished = YES;
+            return;
+        }
+        
+        self.finished = NO;
+        self.executing = YES;
+        
+        if (self.executionBlock) {
+            self.executionBlock(self);
+        } else {
+            self.executing = NO;
+            self.finished = YES;
+        }
     }
 }
 
 - (void)cancel {
-    [super cancel];
-    [self complete];
+    @synchronized (self) {
+        [super cancel];
+        if (self.isExecuting) {
+            self.executing = NO;
+            self.finished = YES;
+        }
+    }
 }
 
+ 
 - (void)complete {
-    [self willChangeValueForKey:@"isExecuting"];
+    @synchronized (self) {
+        if (self.isExecuting) {
+            self.finished = YES;
+            self.executing = NO;
+        }
+    }
+ }
+
+- (void)setFinished:(BOOL)finished {
     [self willChangeValueForKey:@"isFinished"];
-    self.executing = NO;
-    self.finished = YES;
-    [self didChangeValueForKey:@"isExecuting"];
+    _finished = finished;
     [self didChangeValueForKey:@"isFinished"];
 }
 
+- (void)setExecuting:(BOOL)executing {
+    [self willChangeValueForKey:@"isExecuting"];
+    _executing = executing;
+    [self didChangeValueForKey:@"isExecuting"];
+}
+
+- (BOOL)isConcurrent {
+    return YES;
+}
+
 @end

+ 4 - 0
Tests/Tests/SDWebImageDownloaderTests.m

@@ -95,6 +95,10 @@
     operation = token.downloadOperation;
     expect([operation class]).to.equal([SDWebImageTestDownloadOperation class]);
     
+    // Assert the NSOperation conforms to `SDWebImageOperation`
+    expect([NSOperation.class conformsToProtocol:@protocol(SDWebImageOperation)]).beTruthy();
+    expect([operation conformsToProtocol:@protocol(SDWebImageOperation)]).beTruthy();
+    
     // back to the original value
     downloader.config.operationClass = nil;
     token = [downloader downloadImageWithURL:imageURL3 options:0 progress:nil completed:nil];

+ 2 - 2
WebImage/Info.plist

@@ -15,11 +15,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>5.7.3</string>
+	<string>5.7.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>5.7.3</string>
+	<string>5.7.4</string>
 	<key>NSPrincipalClass</key>
 	<string></string>
 </dict>