上一篇我们主要介绍了下SDImageCache的方法的含义和实现,这篇主要介绍SDImageCache的重点方法。
一、这个方法在缓存中查询对应key的图片信息 包含image,diskData以及缓存的类型返回一个NSOperation
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {
if (!key) { //若key == nil ,直接返回,判空
if (doneBlock) {
doneBlock(nil, nil, SDImageCacheTypeNone);
}
return nil;
}
// First check the in-memory cache... 第一步:从内存中取出image
UIImage *image = [self imageFromMemoryCacheForKey:key]; //从缓存当中取出image
if (image) {
NSData *diskData = nil;
if (image.images) {//如果是gif图像,这从disk中提取完整图像
diskData = [self diskImageDataBySearchingAllPathsForKey:key];
}
if (doneBlock) {
doneBlock(image, diskData, SDImageCacheTypeMemory);
}
return nil;
}
NSOperation *operation = [NSOperation new];
dispatch_async(self.ioQueue, ^{ // 异步
if (operation.isCancelled) { //如果当前operation 为caneclled 直接返回
// do not call the completion if cancelled
return;
}
@autoreleasepool {
//到这里说明已经来到磁盘缓存区获取 然后回调结束
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
UIImage *diskImage = [self diskImageForKey:key];
if (diskImage && self.config.shouldCacheImagesInMemory) {//如果有值,并且为shouldCacheImagesInMemory的时候将image缓存起来
NSUInteger cost = SDCacheCostForImage(diskImage); //获取图片字节数
[self.memCache setObject:diskImage forKey:key cost:cost];
}
if (doneBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
});
}
}
});
return operation;
}
二、应用进入后台的时候,调用这个方法 然后清除过期图片
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearMemory)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deleteOldFiles)
name:UIApplicationWillTerminateNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundDeleteOldFiles)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
- (void)backgroundDeleteOldFiles {
Class UIApplicationClass = NSClassFromString(@"UIApplication");
if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) {
return;
}
UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
[self deleteOldFilesWithCompletionBlock:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
}
方法通过向iOS申请,在后台完成一个Long-Running Task任务,当一个 iOS 应用被送到后台,它的主线程会被暂停。你用 NSThread 的 detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。
如果你想在后台完成一个长期任务,就必须调用 UIApplication 的 beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 借点时间。
默认情况下,如果在这个期限内,长期任务没有被完成,iOS 将终止程序。
怎么办?可以使用 beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 再借点时间。经过证明,即使时执行Long-Running Task 任务,当程序被调到后台后,也是有时间限制的。一般为10分总(600s)
三、SDImageCacheConfig,缓存配置对象,包含所有配置项(解压缩图像,iCloud备份, 最长缓存时间,等等)我们自己在封装类的时候,应该学习这种方式
/**
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
* 解压缩图像下载和缓存可以提高性能,但会消耗大量的内存。
* 默认为yes。如果由于内存消耗过多而发生崩溃,请将此设置为NO。
*/
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* disable iCloud backup [defaults to YES]
是否禁用iCloud备份, 默认为YES
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud;
/**
* use memory cache [defaults to YES]
是否缓存到内存中,默认为YES
*/
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
/**
* The reading options while reading cache from disk.
* Defaults to 0. You can set this to mapped file to improve performance.
最大的缓存不过期时间, 单位为秒,默认为一周的时间
*/
@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;
/**
* The maximum length of time to keep an image in the cache, in seconds.
最长缓存时间 默认为1周
*/
@property (assign, nonatomic) NSInteger maxCacheAge;
/**
* The maximum size of the cache, in bytes.
最大的缓存的size,单位是字节
*/
@property (assign, nonatomic) NSUInteger maxCacheSize;
四、NSCache
NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存,它与集合的不同如下:
- NSCache具有自动删除的功能,以减少系统占用的内存;
- NSCache是线程安全的,不需要加线程锁;
- 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)。
添加到缓存
- (nullable ObjectType)objectForKey:(KeyType)key;
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
删除缓存指定key
- (void)removeObjectForKey:(KeyType)key;
删除全部
- (void)removeAllObjects;
totalCostLimit:设置缓存占用的内存大小,并不是一个严格的限制,当总数超过了totalCostLimit设定的值,系统会清除一部分缓存,直至总消耗低于totalCostLimit的值
countLimit:设置缓存对象的大小,这也不是一个严格的限制。
代理方法
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
第一个参数是当前缓存(NSCache),不要修改该对象;
第二个参数是当前将要被清理的对象,如果需要存储该对象,可以在此操作(存入Sqlite or CoreData);
五、计算图片大小(内联函数)
FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
#if SD_MAC
return image.size.height * image.size.width;
#elif SD_UIKIT || SD_WATCH
return image.size.height * image.size.width * image.scale * image.scale;
#endif
}