SDWebImage3——缓存的清除和操作的取消
一、清除缓存和操作最方便放在那里
当我们的app需要在多个控制器上显示图片的时候,如果发生内存警告,我们想自己来清除缓存。那么我应该放在什么地方呢?
可以放在控制器中,不过多个控制器都用来了,需要每个地方都来写,感觉有点淡淡的忧伤
放到 AppDelegate 中,这样我们只需要写一次就行啦。
二、缓存清除方法
清除缓存的方法,我们可以通过 SDWebImageManager 的单例中的 imageCache对象的方法来调用。如
[[SDWebImageManager sharedManager].imageCache clearMemory];
2.1 clearMemory清除内存
清除内存缓存,我们可以使用如下的方法
[[SDWebImageManager sharedManager].imageCache clearMemory];
那么它到底干了一些什么事情呢,我们去看看
这个方法在 SDImageCache中,如下
//清除内存缓存
- (void)clearMemory {
//把所有的内存缓存都删除
[self.memCache removeAllObjects];
}
简单粗暴,删除所有内存缓存
2.2 clearDisk清除磁盘
清除内存缓存,我们可以使用如下的方法
[[SDWebImageManager sharedManager].imageCache clearMemory];
那么它到底干了一些什么事情呢,我们去看看
这个方法在 SDImageCache中,如下
//清除磁盘缓存
- (void)clearDisk {
[self clearDiskOnCompletion:nil];
}
//清除磁盘缓存(简单粗暴)
- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion
{
//开子线程异步处理 清理磁盘缓存的操作
dispatch_async(self.ioQueue, ^{
//删除缓存路径
[_fileManager removeItemAtPath:self.diskCachePath error:nil];
//重新创建缓存路径
[_fileManager createDirectoryAtPath:self.diskCachePath
withIntermediateDirectories:YES
attributes:nil
error:NULL];
if (completion) {
//在主线程中处理completion回调
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}
});
}
同样这个清除磁盘的方式也是一样,直接删除缓存文件夹,然后在创建一个空的文件夹,完成这些操作以后,去主线中处理 completion回调。
2.2 cleanDisk清除磁盘
这个方法清除磁盘,主要从两个方面出发,
第一、文件过期那么清除,
第二、计算当前缓存的大小,和设置的最大缓存数量比较,如果超出那么会继续删除(按照文件了创建的先后顺序)
这个方法在 SDImageCache中,如下
//清除过期的磁盘缓存
- (void)cleanDisk {
[self cleanDiskWithCompletionBlock:nil];
}
//清除过期的磁盘缓存
- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock {
dispatch_async(self.ioQueue, ^{
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
// This enumerator prefetches useful properties for our cache files.
NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
includingPropertiesForKeys:resourceKeys
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:NULL];
// 计算过期日期
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
NSUInteger currentCacheSize = 0;
// Enumerate all of the files in the cache directory. This loop has two purposes:
//
// 1. Removing files that are older than the expiration date.
// 2. Storing file attributes for the size-based cleanup pass.
// 遍历缓存路径中的所有文件,此循环要实现两个目的
// 1. 删除早于过期日期的文件
// 2. 保存文件属性以计算磁盘缓存占用空间
NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init];
for (NSURL *fileURL in fileEnumerator) {
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];
// Skip directories.
// 跳过目录
if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
continue;
}
// Remove files that are older than the expiration date;
// 记录要删除的过期文件
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
[urlsToDelete addObject:fileURL];
continue;
}
// Store a reference to this file and account for its total size.
//保存文件引用,以计算总大小
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize += [totalAllocatedSize unsignedIntegerValue];
[cacheFiles setObject:resourceValues forKey:fileURL];
}
// 删除过期的文件
for (NSURL *fileURL in urlsToDelete) {
[_fileManager removeItemAtURL:fileURL error:nil];
}
// If our remaining disk cache exceeds a configured maximum size, perform a second
// size-based cleanup pass. We delete the oldest files first.
//如果剩余磁盘缓存空间超出最大限额,再次执行清理操作,删除最早的文件
if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize) {
// Target half of our maximum cache size for this cleanup pass.
const NSUInteger desiredCacheSize = self.maxCacheSize / 2;
// Sort the remaining cache files by their last modification time (oldest first).
NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
usingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]];
}];
// Delete files until we fall below our desired cache size.
// 循环依次删除文件,直到低于期望的缓存限额
for (NSURL *fileURL in sortedFiles) {
if ([_fileManager removeItemAtURL:fileURL error:nil]) {
NSDictionary *resourceValues = cacheFiles[fileURL];
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
if (currentCacheSize < desiredCacheSize) {
break;
}
}
}
}
//在主线程中处理完成回调
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock();
});
}
});
}
2.4 最大缓存时间
上面我们涉及到了最大缓存时间,那么它的值是多少呢?
SDImageCache 的下面方法中定义了这个默认值
//使用指定的命名空间实例化一个新的缓存存储和目录
- (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory {
......
//初始化默认的最大缓存时间 == 1周
_maxCacheAge = kDefaultCacheMaxCacheAge;
......
}
我们再来看看 kDefaultCacheMaxCacheAge
//默认的最大缓存时间为1周
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
所以默认最大缓存时间是一个周。
2.5 最大缓存大小
上面我们知道,cleanDisk 的时候,除了时间,还有缓存的大小也是判断的依据,那么我们来看看,最大的缓存大小。
/**
* The maximum size of the cache, in bytes.
*
* 缓存图像总大小,以字节为单位,默认数值为0,表示不作限制
*/
@property (assign, nonatomic) NSUInteger maxCacheSize;
三、取消操作
//取消当前的所有操作
[[SDWebImageManager sharedManager] cancelAll];
四、示例代码
//
// AppDelegate.m
// 03_UIview87_SDWebImage
//
// Created by 杞文明 on 17/9/7.
// Copyright © 2017年 杞文明. All rights reserved.
//
#import "AppDelegate.h"
#import "SDWebImageManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{
//1.清空缓存
//clear:直接删除缓存目录下面的文件,然后重新创建空的缓存文件
//clean:清除过期缓存,计算当前缓存的大小,和设置的最大缓存数量比较,如果超出那么会继续删除(按照文件了创建的先后顺序)
//过期时间:7天
[[SDWebImageManager sharedManager].imageCache cleanDisk];
// [[SDWebImageManager sharedManager].imageCache clearMemory];
//2.取消当前的所有操作
[[SDWebImageManager sharedManager] cancelAll];
}
@end