From 7b02207537d35bfa1714bf8beafc921f717d100a Mon Sep 17 00:00:00 2001
From: 单军华
Date: Wed, 11 Jul 2018 10:47:42 +0800
Subject: [PATCH] 首次上传
---
screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageManager.m | 366 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 366 insertions(+), 0 deletions(-)
diff --git a/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageManager.m b/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageManager.m
new file mode 100644
index 0000000..fa529e7
--- /dev/null
+++ b/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageManager.m
@@ -0,0 +1,366 @@
+/*
+ * 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 "SDWebImageManager.h"
+#import "NSImage+WebCache.h"
+#import <objc/message.h>
+
+#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
+#define UNLOCK(lock) dispatch_semaphore_signal(lock);
+
+@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
+
+@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
+@property (strong, nonatomic, nullable) SDWebImageDownloadToken *downloadToken;
+@property (strong, nonatomic, nullable) NSOperation *cacheOperation;
+@property (weak, nonatomic, nullable) SDWebImageManager *manager;
+
+@end
+
+@interface SDWebImageManager ()
+
+@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache;
+@property (strong, nonatomic, readwrite, nonnull) SDWebImageDownloader *imageDownloader;
+@property (strong, nonatomic, nonnull) NSMutableSet<NSURL *> *failedURLs;
+@property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe
+@property (strong, nonatomic, nonnull) NSMutableArray<SDWebImageCombinedOperation *> *runningOperations;
+@property (strong, nonatomic, nonnull) dispatch_semaphore_t runningOperationsLock; // a lock to keep the access to `runningOperations` thread-safe
+
+@end
+
+@implementation SDWebImageManager
+
++ (nonnull instancetype)sharedManager {
+ static dispatch_once_t once;
+ static id instance;
+ dispatch_once(&once, ^{
+ instance = [self new];
+ });
+ return instance;
+}
+
+- (nonnull instancetype)init {
+ SDImageCache *cache = [SDImageCache sharedImageCache];
+ SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader];
+ return [self initWithCache:cache downloader:downloader];
+}
+
+- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader {
+ if ((self = [super init])) {
+ _imageCache = cache;
+ _imageDownloader = downloader;
+ _failedURLs = [NSMutableSet new];
+ _failedURLsLock = dispatch_semaphore_create(1);
+ _runningOperations = [NSMutableArray new];
+ _runningOperationsLock = dispatch_semaphore_create(1);
+ }
+ return self;
+}
+
+- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url {
+ if (!url) {
+ return @"";
+ }
+
+ if (self.cacheKeyFilter) {
+ return self.cacheKeyFilter(url);
+ } else {
+ return url.absoluteString;
+ }
+}
+
+- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image {
+ return SDScaledImageForKey(key, image);
+}
+
+- (void)cachedImageExistsForURL:(nullable NSURL *)url
+ completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
+ NSString *key = [self cacheKeyForURL:url];
+
+ BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
+
+ if (isInMemoryCache) {
+ // making sure we call the completion block on the main queue
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (completionBlock) {
+ completionBlock(YES);
+ }
+ });
+ return;
+ }
+
+ [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
+ // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
+ if (completionBlock) {
+ completionBlock(isInDiskCache);
+ }
+ }];
+}
+
+- (void)diskImageExistsForURL:(nullable NSURL *)url
+ completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
+ NSString *key = [self cacheKeyForURL:url];
+
+ [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
+ // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
+ if (completionBlock) {
+ completionBlock(isInDiskCache);
+ }
+ }];
+}
+
+- (id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
+ options:(SDWebImageOptions)options
+ progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
+ completed:(nullable SDInternalCompletionBlock)completedBlock {
+ // Invoking this method without a completedBlock is pointless
+ NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
+
+ // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, Xcode won't
+ // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
+ if ([url isKindOfClass:NSString.class]) {
+ url = [NSURL URLWithString:(NSString *)url];
+ }
+
+ // Prevents app crashing on argument type error like sending NSNull instead of NSURL
+ if (![url isKindOfClass:NSURL.class]) {
+ url = nil;
+ }
+
+ SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
+ operation.manager = self;
+
+ BOOL isFailedUrl = NO;
+ if (url) {
+ LOCK(self.failedURLsLock);
+ isFailedUrl = [self.failedURLs containsObject:url];
+ UNLOCK(self.failedURLsLock);
+ }
+
+ if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
+ [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url];
+ return operation;
+ }
+
+ LOCK(self.runningOperationsLock);
+ [self.runningOperations addObject:operation];
+ UNLOCK(self.runningOperationsLock);
+ NSString *key = [self cacheKeyForURL:url];
+
+ SDImageCacheOptions cacheOptions = 0;
+ if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory;
+ if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync;
+ if (options & SDWebImageScaleDownLargeImages) cacheOptions |= SDImageCacheScaleDownLargeImages;
+
+ __weak SDWebImageCombinedOperation *weakOperation = operation;
+ operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
+ __strong __typeof(weakOperation) strongOperation = weakOperation;
+ if (!strongOperation || strongOperation.isCancelled) {
+ [self safelyRemoveOperationFromRunning:strongOperation];
+ return;
+ }
+
+ // Check whether we should download image from network
+ BOOL shouldDownload = (!(options & SDWebImageFromCacheOnly))
+ && (!cachedImage || options & SDWebImageRefreshCached)
+ && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]);
+ if (shouldDownload) {
+ if (cachedImage && options & SDWebImageRefreshCached) {
+ // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image
+ // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
+ [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
+ }
+
+ // download if no image or requested to refresh anyway, and download allowed by delegate
+ SDWebImageDownloaderOptions downloaderOptions = 0;
+ if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
+ if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
+ if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
+ if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
+ if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
+ if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
+ if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
+ if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages;
+
+ if (cachedImage && options & SDWebImageRefreshCached) {
+ // force progressive off if image already cached but forced refreshing
+ downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
+ // ignore image read from NSURLCache if image if cached but force refreshing
+ downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
+ }
+
+ // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle
+ __weak typeof(strongOperation) weakSubOperation = strongOperation;
+ strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) {
+ __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation;
+ if (!strongSubOperation || strongSubOperation.isCancelled) {
+ // Do nothing if the operation was cancelled
+ // See #699 for more details
+ // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
+ } else if (error) {
+ [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock error:error url:url];
+ BOOL shouldBlockFailedURL;
+ // Check whether we should block failed url
+ if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) {
+ shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error];
+ } else {
+ shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet
+ && error.code != NSURLErrorCancelled
+ && error.code != NSURLErrorTimedOut
+ && error.code != NSURLErrorInternationalRoamingOff
+ && error.code != NSURLErrorDataNotAllowed
+ && error.code != NSURLErrorCannotFindHost
+ && error.code != NSURLErrorCannotConnectToHost
+ && error.code != NSURLErrorNetworkConnectionLost);
+ }
+
+ if (shouldBlockFailedURL) {
+ LOCK(self.failedURLsLock);
+ [self.failedURLs addObject:url];
+ UNLOCK(self.failedURLsLock);
+ }
+ }
+ else {
+ if ((options & SDWebImageRetryFailed)) {
+ LOCK(self.failedURLsLock);
+ [self.failedURLs removeObject:url];
+ UNLOCK(self.failedURLsLock);
+ }
+
+ BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
+
+ // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale.
+ if (self != [SDWebImageManager sharedManager] && self.cacheKeyFilter && downloadedImage) {
+ downloadedImage = [self scaledImageForKey:key image:downloadedImage];
+ }
+
+ if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) {
+ // Image refresh hit the NSURLCache cache, do not call the completion block
+ } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+ UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
+
+ if (transformedImage && finished) {
+ BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
+ NSData *cacheData;
+ // pass nil if the image was transformed, so we can recalculate the data from the image
+ if (self.cacheSerializer) {
+ cacheData = self.cacheSerializer(transformedImage, (imageWasTransformed ? nil : downloadedData), url);
+ } else {
+ cacheData = (imageWasTransformed ? nil : downloadedData);
+ }
+ [self.imageCache storeImage:transformedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil];
+ }
+
+ [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
+ });
+ } else {
+ if (downloadedImage && finished) {
+ if (self.cacheSerializer) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+ NSData *cacheData = self.cacheSerializer(downloadedImage, downloadedData, url);
+ [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil];
+ });
+ } else {
+ [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];
+ }
+ }
+ [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
+ }
+ }
+
+ if (finished) {
+ [self safelyRemoveOperationFromRunning:strongSubOperation];
+ }
+ }];
+ } else if (cachedImage) {
+ [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
+ [self safelyRemoveOperationFromRunning:strongOperation];
+ } else {
+ // Image not in cache and download disallowed by delegate
+ [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url];
+ [self safelyRemoveOperationFromRunning:strongOperation];
+ }
+ }];
+
+ return operation;
+}
+
+- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url {
+ if (image && url) {
+ NSString *key = [self cacheKeyForURL:url];
+ [self.imageCache storeImage:image forKey:key toDisk:YES completion:nil];
+ }
+}
+
+- (void)cancelAll {
+ LOCK(self.runningOperationsLock);
+ NSArray<SDWebImageCombinedOperation *> *copiedOperations = [self.runningOperations copy];
+ UNLOCK(self.runningOperationsLock);
+ [copiedOperations makeObjectsPerformSelector:@selector(cancel)]; // This will call `safelyRemoveOperationFromRunning:` and remove from the array
+}
+
+- (BOOL)isRunning {
+ BOOL isRunning = NO;
+ LOCK(self.runningOperationsLock);
+ isRunning = (self.runningOperations.count > 0);
+ UNLOCK(self.runningOperationsLock);
+ return isRunning;
+}
+
+- (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation {
+ if (!operation) {
+ return;
+ }
+ LOCK(self.runningOperationsLock);
+ [self.runningOperations removeObject:operation];
+ UNLOCK(self.runningOperationsLock);
+}
+
+- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation
+ completion:(nullable SDInternalCompletionBlock)completionBlock
+ error:(nullable NSError *)error
+ url:(nullable NSURL *)url {
+ [self callCompletionBlockForOperation:operation completion:completionBlock image:nil data:nil error:error cacheType:SDImageCacheTypeNone finished:YES url:url];
+}
+
+- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation
+ completion:(nullable SDInternalCompletionBlock)completionBlock
+ image:(nullable UIImage *)image
+ data:(nullable NSData *)data
+ error:(nullable NSError *)error
+ cacheType:(SDImageCacheType)cacheType
+ finished:(BOOL)finished
+ url:(nullable NSURL *)url {
+ dispatch_main_async_safe(^{
+ if (operation && !operation.isCancelled && completionBlock) {
+ completionBlock(image, data, error, cacheType, finished, url);
+ }
+ });
+}
+
+@end
+
+
+@implementation SDWebImageCombinedOperation
+
+- (void)cancel {
+ @synchronized(self) {
+ self.cancelled = YES;
+ if (self.cacheOperation) {
+ [self.cacheOperation cancel];
+ self.cacheOperation = nil;
+ }
+ if (self.downloadToken) {
+ [self.manager.imageDownloader cancel:self.downloadToken];
+ }
+ [self.manager safelyRemoveOperationFromRunning:self];
+ }
+}
+
+@end
--
Gitblit v1.8.0