Use a dispatch semaphore to keep thread safe for downloader because it need the hold cancel and add procedure be thread-safe
This commit is contained in:
parent
f2d9abbc4a
commit
311c9e1a5e
|
@ -9,6 +9,9 @@
|
||||||
#import "SDWebImageDownloader.h"
|
#import "SDWebImageDownloader.h"
|
||||||
#import "SDWebImageDownloaderOperation.h"
|
#import "SDWebImageDownloaderOperation.h"
|
||||||
|
|
||||||
|
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||||
|
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||||
|
|
||||||
@interface SDWebImageDownloadToken ()
|
@interface SDWebImageDownloadToken ()
|
||||||
|
|
||||||
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperationInterface> *downloadOperation;
|
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperationInterface> *downloadOperation;
|
||||||
|
@ -36,6 +39,7 @@
|
||||||
@property (assign, nonatomic, nullable) Class operationClass;
|
@property (assign, nonatomic, nullable) Class operationClass;
|
||||||
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> *URLOperations;
|
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> *URLOperations;
|
||||||
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
|
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
|
||||||
|
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe
|
||||||
|
|
||||||
// The session in which data tasks will run
|
// The session in which data tasks will run
|
||||||
@property (strong, nonatomic) NSURLSession *session;
|
@property (strong, nonatomic) NSURLSession *session;
|
||||||
|
@ -94,6 +98,7 @@
|
||||||
#else
|
#else
|
||||||
_HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
|
_HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
|
||||||
#endif
|
#endif
|
||||||
|
_operationsLock = dispatch_semaphore_create(1);
|
||||||
_downloadTimeout = 15.0;
|
_downloadTimeout = 15.0;
|
||||||
|
|
||||||
[self createNewSessionWithConfiguration:sessionConfiguration];
|
[self createNewSessionWithConfiguration:sessionConfiguration];
|
||||||
|
@ -232,12 +237,16 @@
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDWebImageDownloaderOperation *operation = [self operationForURL:url];
|
LOCK(self.operationsLock);
|
||||||
|
SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
|
||||||
|
if (operation) {
|
||||||
BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
|
BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
[self removeOperationForURL:url];
|
[self.URLOperations removeObjectForKey:url];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UNLOCK(self.operationsLock);
|
||||||
|
}
|
||||||
|
|
||||||
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
|
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
|
||||||
completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
|
completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
|
||||||
|
@ -251,17 +260,24 @@
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDWebImageDownloaderOperation *operation = [self operationForURL:url];
|
LOCK(self.operationsLock);
|
||||||
|
SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
|
||||||
if (!operation) {
|
if (!operation) {
|
||||||
operation = createCallback();
|
operation = createCallback();
|
||||||
[self setOperation:operation forURL:url];
|
|
||||||
|
|
||||||
__weak typeof(self) wself = self;
|
__weak typeof(self) wself = self;
|
||||||
operation.completionBlock = ^{
|
operation.completionBlock = ^{
|
||||||
__strong typeof(wself) sself = wself;
|
__strong typeof(wself) sself = wself;
|
||||||
[sself removeOperationForURL:url];
|
if (!sself) {
|
||||||
};
|
return;
|
||||||
}
|
}
|
||||||
|
LOCK(sself.operationsLock);
|
||||||
|
[sself.URLOperations removeObjectForKey:url];
|
||||||
|
UNLOCK(sself.operationsLock);
|
||||||
|
};
|
||||||
|
[self.URLOperations setObject:operation forKey:url];
|
||||||
|
}
|
||||||
|
UNLOCK(self.operationsLock);
|
||||||
|
|
||||||
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
|
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
|
||||||
|
|
||||||
SDWebImageDownloadToken *token = [SDWebImageDownloadToken new];
|
SDWebImageDownloadToken *token = [SDWebImageDownloadToken new];
|
||||||
|
@ -282,35 +298,6 @@
|
||||||
|
|
||||||
#pragma mark Helper methods
|
#pragma mark Helper methods
|
||||||
|
|
||||||
- (SDWebImageDownloaderOperation *)operationForURL:(NSURL *)url {
|
|
||||||
if (!url) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
SDWebImageDownloaderOperation *operation;
|
|
||||||
@synchronized (self.URLOperations) {
|
|
||||||
operation = [self.URLOperations objectForKey:url];
|
|
||||||
}
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setOperation:(SDWebImageDownloaderOperation *)operation forURL:(NSURL *)url {
|
|
||||||
if (!operation || !url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@synchronized (self.URLOperations) {
|
|
||||||
[self.URLOperations setObject:operation forKey:url];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeOperationForURL:(NSURL *)url {
|
|
||||||
if (!url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@synchronized (self.URLOperations) {
|
|
||||||
[self.URLOperations removeObjectForKey:url];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task {
|
- (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task {
|
||||||
SDWebImageDownloaderOperation *returnOperation = nil;
|
SDWebImageDownloaderOperation *returnOperation = nil;
|
||||||
for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) {
|
for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) {
|
||||||
|
|
Loading…
Reference in New Issue