版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.02.12 |
前言
我们做APP,文字和图片是绝对不可缺少的元素,特别是图片一般存储在图床里面,一般公司可以委托第三方保存,NB的公司也可以自己存储图片,ios有很多图片加载的第三方框架,其中最优秀的莫过于SDWebImage,它几乎可以满足你所有的需求,用了好几年这个框架,今天想总结一下。感兴趣的可以看其他几篇。
1. SDWebImage探究(一)
2. SDWebImage探究(二)
3. SDWebImage探究(三)
4. SDWebImage探究(四)
5. SDWebImage探究(五)
6. SDWebImage探究(六) —— 图片类型判断深入研究
7. SDWebImage探究(七) —— 深入研究图片下载流程(一)之有关option的位移枚举的说明
8. SDWebImage探究(八) —— 深入研究图片下载流程(二)之开始下载并返回下载结果的总的方法
9. SDWebImage探究(九) —— 深入研究图片下载流程(三)之下载之前的缓存查询操作
回顾
从上面一篇可见,通过查询缓存获取了数据,这一篇就主要讲述一下查询后的block回调,一共回调三个参数UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType
。
查询回调函数的处理
1. 检查操作是否被取消
首先是判断SDWebImageCombinedOperation *operation
的是否别取消。
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
if (operation.isCancelled) {
[self safelyRemoveOperationFromRunning:operation];
return;
}
如果operation被取消了,就会使用方法safelyRemoveOperationFromRunning:
,将该操作从集合中移除。
- (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation {
@synchronized (self.runningOperations) {
if (operation) {
[self.runningOperations removeObject:operation];
}
}
}
2. 几个if-else逻辑处理
第1个条件判断
1)先看第一个判断条件
if ((!cachedImage || options & SDWebImageRefreshCached)
&& (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)]
|| [self.delegate imageManager:self shouldDownloadImageForURL:url]))
然后进行进一步计算
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:weakOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
}
如果缓存图像不为空,并且options为SDWebImageRefreshCached
,并且调用下面方法返回completionBlock
- (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);
}
});
}
2) SDWebImageDownloaderOptions
配置条件
下面就是这个枚举变量的配置逻辑。
// 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;
}
这里根据传入的那个SDWebImageOptions
类型配置SDWebImageDownloaderOptions
类型的变量。我们可以看一下这个枚举定义的API
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
SDWebImageDownloaderLowPriority = 1 << 0,
SDWebImageDownloaderProgressiveDownload = 1 << 1,
/**
* By default, request prevent the use of NSURLCache. With this flag, NSURLCache
* is used with default policies.
*/
SDWebImageDownloaderUseNSURLCache = 1 << 2,
/**
* Call completion block with nil image/imageData if the image was read from NSURLCache
* (to be combined with `SDWebImageDownloaderUseNSURLCache`).
* I think this option should be renamed to 'SDWebImageDownloaderUsingCachedResponseDontLoad'
*/
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
SDWebImageDownloaderContinueInBackground = 1 << 4,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
SDWebImageDownloaderHandleCookies = 1 << 5,
/**
* Enable to allow untrusted SSL certificates.
* Useful for testing purposes. Use with caution in production.
*/
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,
/**
* Put the image in the high priority queue.
*/
SDWebImageDownloaderHighPriority = 1 << 7,
/**
* Scale down the image
*/
SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
};
3) 调用下载器SDWebImageDownloader
进行下载
直接使用下载器进行下载
/**
* Creates a SDWebImageDownloader async downloader instance with a given URL
*
* The delegate will be informed when the image is finish downloaded or an error has happen.
*
* @see SDWebImageDownloaderDelegate
*
* @param url The URL to the image to download
* @param options The options to be used for this download
* @param progressBlock A block called repeatedly while the image is downloading
* @note the progress block is executed on a background queue
* @param completedBlock A block called once the download is completed.
* If the download succeeded, the image parameter is set, in case of error,
* error parameter is set with the error. The last parameter is always YES
* if SDWebImageDownloaderProgressiveDownload isn't use. With the
* SDWebImageDownloaderProgressiveDownload option, this block is called
* repeatedly with the partial image object and the finished argument set to NO
* before to be called a last time with the full image and finished argument
* set to YES. In case of error, the finished argument is always YES.
*
* @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation
*/
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
这个方法返回的是SDWebImageDownloadToken
对象。下载回调的参数如下UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished
,一共四个参数。如果if (!strongOperation || strongOperation.isCancelled)
就什么都不做;如果error
不为空,作如下处理:
[self callCompletionBlockForOperation:strongOperation completion:completedBlock error:error url:url];
if ( error.code != NSURLErrorNotConnectedToInternet
&& error.code != NSURLErrorCancelled
&& error.code != NSURLErrorTimedOut
&& error.code != NSURLErrorInternationalRoamingOff
&& error.code != NSURLErrorDataNotAllowed
&& error.code != NSURLErrorCannotFindHost
&& error.code != NSURLErrorCannotConnectToHost
&& error.code != NSURLErrorNetworkConnectionLost) {
@synchronized (self.failedURLs) {
[self.failedURLs addObject:url];
}
}
这里,首先使用下面方法给出completionBlock
回调
- (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);
}
});
}
并使用锁,将把失败的url放入集合中。
如果上面if不成立并且error为空时,就会做如下处理:
这里下载的图像回来就会根据条件进行图像的变换以及存储,如下所示:
/**
* Asynchronously store an image into memory and disk cache at the given key.
*
* @param image The image to store
* @param imageData The image data as returned by the server, this representation will be used for disk storage
* instead of converting the given image object into a storable/compressed image format in order
* to save quality and CPU
* @param key The unique image cache key, usually it's image absolute URL
* @param toDisk Store the image to disk cache if YES
* @param completionBlock A block executed after the operation is finished
*/
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
根据指定的路径存在内存和disk。并调用callCompletionBlockForOperation:
回调completionBlock
。
第2个条件判断
条件是else if (cachedImage)
,如果缓存图像不为空。
__strong __typeof(weakOperation) strongOperation = weakOperation;
[self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
[self safelyRemoveOperationFromRunning:operation];
这里操作还是回调block和从操作数组中移除操作。
第3个条件判断
剩下的情况,如下处理:
// Image not in cache and download disallowed by delegate
__strong __typeof(weakOperation) strongOperation = weakOperation;
[self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url];
[self safelyRemoveOperationFromRunning:operation];
这里操作还是回调block和从操作数组中移除操作。这个和上面不同的是图像、图像NSData数据和缓存类型分别为nil、nil和SDImageCacheTypeNone
。
最后返回就是SDWebImageCombinedOperation *operation
对象。
后记
本篇已结束,后面更精彩~~~