SDWebImageDownloader
核心方法
```
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
context:(nullableSDWebImageContext*)context
progress:(nullableSDWebImageDownloaderProgressBlock)progressBlock
completed:(nullableSDWebImageDownloaderCompletedBlock)completedBlock {
// The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
if(url ==nil) {
if(completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}];
completedBlock(nil,nil, error,YES);
}
returnnil;
}
SD_LOCK(self.operationsLock);
iddownloadOperationCancelToken;
NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
// There is a case that the operation may be marked as finished or cancelled, but not been removed from `self.URLOperations`.
if(!operation || operation.isFinished|| operation.isCancelled) {
operation = [selfcreateDownloaderOperationWithUrl:urloptions:optionscontext:context];
if(!operation) {
SD_UNLOCK(self.operationsLock);
if(completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}];
completedBlock(nil,nil, error,YES);
}
returnnil;
}
@weakify(self);
operation.completionBlock= ^{
@strongify(self);
if(!self) {
return;
}
SD_LOCK(self.operationsLock);
[self.URLOperationsremoveObjectForKey:url];
SD_UNLOCK(self.operationsLock);
};
self.URLOperations[url] = operation;
// Add operation to operation queue only after all configuration done according to Apple's doc.
// `addOperation:` does not synchronously execute the `operation.completionBlock` so this will not cause deadlock.
[self.downloadQueueaddOperation:operation];
downloadOperationCancelToken = [operationaddHandlersForProgress:progressBlockcompleted:completedBlock];
}else{
// When we reuse the download operation to attach more callbacks, there may be thread safe issue because the getter of callbacks may in another queue (decoding queue or delegate queue)
// So we lock the operation here, and in `SDWebImageDownloaderOperation`, we use `@synchonzied (self)`, to ensure the thread safe between these two classes.
@synchronized(operation) {
downloadOperationCancelToken = [operationaddHandlersForProgress:progressBlockcompleted:completedBlock];
}
if(!operation.isExecuting) {
if (options & SDWebImageDownloaderHighPriority) {
operation.queuePriority = NSOperationQueuePriorityHigh;
}else if (options & SDWebImageDownloaderLowPriority) {
operation.queuePriority = NSOperationQueuePriorityLow;
}else{
operation.queuePriority = NSOperationQueuePriorityNormal;
}
}
}
SD_UNLOCK(self.operationsLock);
SDWebImageDownloadToken *token = [[SDWebImageDownloadToken alloc] initWithDownloadOperation:operation];
token.url= url;
token.request= operation.request;
token.downloadOperationCancelToken= downloadOperationCancelToken;
returntoken;
}
```
网友评论