在网络编程当中,如果我们能将向网络请求的图片缓存在本地当中,这将大大的提高我们重复加载图片的速度,使得用户体验更加的好。图片缓存的原理是以网络链接为原型,然后进行格式化的转换,形成一个新的名称,以这个名称作为图片缓存在本地的文件名(一般使用哈希算法,并且算法要保证几乎不会重复命名)。第二种方式是以字典保存链接,每一个链接对应字典的一个key,图片本身的名字作为value存在,那么在每一次请求图片数据的时候我们就能根据key值找到本地是否存在了缓存的图片名。本文中将使用第一种方式来实现缓存图片,其中只缓存20k大小以下的图片。
首先我使用的是MD5算法来对链接进行处理,最后生成一个新的文件名,MD5转换字符串代码如下:
- (NSString *)translateInMD5
{
const char * originStr = [self UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(originStr, (unsigned int)strlen(originStr), result);
NSMutableString * outputStr = [NSMutableString stringWithCapacity: CC_MD5_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[outputStr appendFormat: @"%02x", result[i]];
}
return outputStr;
}
MD5算法几乎可以保证我们不会生成同名文件,具体MD5实现大家可以百度查看。
图片的缓存方法以UIImageView类category的方式来实现,这样可以提高我们对代码的复用度。其中有两个方法,一个是返回缓存图片的绝对路径,另一个就是实现缓存方法。下面上代码:
实现缓存方法:
- (void)lxdSetImage:(NSString *)imageURL
{
NSString * md5FileName = [imageURL translateInMD5];
NSString * filePath = [self filePathOfCacheDirectoryWithFileName: md5FileName];
NSData * imageData = [NSData dataWithContentsOfFile: filePath];
if (imageData) {
self.image = [UIImage imageWithData: imageData];
return;
}
__weak typeof(self)weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData * imageData = [NSData dataWithContentsOfURL: [NSURL URLWithString: imageURL]];
//现将byte转换为bit(8:1)然后转换为kb(1024:1)
CGFloat thousandBytes = imageData.length * 1.0 / (2 << 2) / (2 << 9);
if (thousandBytes <= 20.0) {
[imageData writeToFile: filePath atomically: YES];
}
weakSelf.image = [UIImage imageWithData: imageData];
});
}
获取图片缓存绝对路径:
- (NSString *)filePathOfCacheDirectoryWithFileName: (NSString *)fileName
{
NSString * documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
return [documentDirectory stringByAppendingPathComponent: [NSString stringWithFormat: @"cache/%@", fileName]];
}
我自定义的缓存方法暂时没有去考虑缓存图片的最大存在时间,我自身的想法包括两种方式来删除过期的缓存图片:
一、在每次缓存图片文件名生成之后,加上一个以当前时间为后缀的字符串,每次读取缓存图片之后异步检测缓存目录下所有图片的后缀名,超出最大保存时间的就使用NSFileManager删除这些文件
二、将缓存图片保存到sqlite中,添加一个当前时间的变量,每次获取缓存图片时同样查询所有缓存时间,超出最大保存时间就删除