SDWebImage 3 -- Cache Clearance and Operation Cancellation
1. Clear the cache and put it there most easily
When our app needs to display pictures on multiple controllers, we want to clear the cache ourselves if a memory warning occurs. So where should I put it?
Can be placed in the controller, but many controllers are used, need to be written everywhere, feeling a little sad.
Put it in AppDelegate, so we only need to write it once.
2. Cache Clearance Method
The method to clear the cache can be invoked through the imageCache object in the SDWeb Image Manager's singleton. as
[[SDWebImageManager sharedManager].imageCache clearMemory];
2.1 Clear Memory Clears Memory
To clear the memory cache, we can use the following methods
[[SDWebImageManager sharedManager].imageCache clearMemory];
So what did it do? Let's go and see.
This method in SDIMAGE Cache is as follows
//Clear memory cache
- (void)clearMemory {
//Delete all memory caches
[self.memCache removeAllObjects];
}
Simple and rude, delete all memory caches
2.2 CleaDisk Clear Disk
To clear the memory cache, we can use the following methods
[[SDWebImageManager sharedManager].imageCache clearMemory];
So what did it do? Let's go and see.
This method in SDIMAGE Cache is as follows
//Clear disk cache
- (void)clearDisk {
[self clearDiskOnCompletion:nil];
}
//Clear the disk cache (simple and rude)
- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion
{
//Open Subthread Asynchronous Processing for Cleaning Disk Cache
dispatch_async(self.ioQueue, ^{
//Delete Cache Path
[_fileManager removeItemAtPath:self.diskCachePath error:nil];
//Recreate Cache Path
[_fileManager createDirectoryAtPath:self.diskCachePath
withIntermediateDirectories:YES
attributes:nil
error:NULL];
if (completion) {
//Processing completion callbacks in the main thread
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}
});
}
The same is true for this way of clearing disks. Delete the cache folder directly, and then create an empty folder. After these operations, go to the main line to process the completion callback.
2.2 Clean Disk Clean Disk
This method of clearing disks is mainly based on two aspects.
Firstly, the documents are so obsolete that they are cleared.
Second, calculate the size of the current cache and compare it with the maximum number of caches set up. If it exceeds that, it will continue to be deleted (in the order in which the files were created).
This method in SDIMAGE Cache is as follows
//Clear out expired disk caches
- (void)cleanDisk {
[self cleanDiskWithCompletionBlock:nil];
}
//Clear out expired disk caches
- (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];
// Calculate expiration date
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.
// Traversing through all files in the cache path, this loop achieves two purposes
// 1. Delete files earlier than expiration date
// 2. Save file attributes to calculate disk cache footprint
NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init];
for (NSURL *fileURL in fileEnumerator) {
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];
// Skip directories.
// Skip directory
if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
continue;
}
// Remove files that are older than the expiration date;
// Record expired files to be deleted
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.
//Save file references to calculate total size
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize += [totalAllocatedSize unsignedIntegerValue];
[cacheFiles setObject:resourceValues forKey:fileURL];
}
// Delete expired files
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 the remaining disk cache space exceeds the maximum, clean up again and delete the earliest files
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.
// Remove files in turn until they are below the expected cache limit
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;
}
}
}
}
//Processing complete callbacks in the main thread
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock();
});
}
});
}
2.4 Maximum Cache Time
We mentioned the maximum cache time above, so what is its value?
This default value is defined in the following method of SDImageCache
// Instantiate a new cache store and directory using the specified namespace
- (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory {
......
// Initialize the default maximum cache time = 1 week
_maxCacheAge = kDefaultCacheMaxCacheAge;
......
}
Let's look at kDefault Cache Max CacheAge again.
// The default maximum cache time is 1 week
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
So the default maximum cache time is one week.
### 2.5 Maximum Cache Size
As we know above, besides the time, the size of the cache is also the basis for judging when cleaning Disk is used. So let's take a look at the largest cache size.
/**
* The maximum size of the cache, in bytes.
*
* The total size of the cached image, in bytes, is 0 by default, indicating no restriction.
*/
@property (assign, nonatomic) NSUInteger maxCacheSize;
III. Cancellation
//Cancel all current operations
[[SDWebImageManager sharedManager] cancelAll];
IV. Sample Code
//
// AppDelegate.m
// 03_UIview87_SDWebImage
//
// Created by Qi Civilization on 17/9/7.
// Copyright 2017 Qi Civilization. All rights reserved.
//
#import "AppDelegate.h"
#import "SDWebImageManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{
//1. Empty the cache
//clear: Delete the files under the cache directory directly and recreate the empty cache files
//clean: clean out expired caches, calculate the size of the current cache, and compare it with the maximum number of caches set. If it exceeds that, it will continue to be deleted (in the order in which the files were created)
//Overdue time: 7 days
[[SDWebImageManager sharedManager].imageCache cleanDisk];
// [[SDWebImageManager sharedManager].imageCache clearMemory];
//2. Cancel all current operations
[[SDWebImageManager sharedManager] cancelAll];
}
@end