因项目中涉及到大量的图片展示问题,当图片累计过多时缓存到本地的图片会比较占本地内存空间,影响用户体验,为了提高用户体验,经过讨论后决定添加七天自动清理缓存功能。项目的图片展示是使用的 SDWebImage(以下简称 SD) 这个三方,评估了一下修改三方原代码可能产生的一系列问题。决定独立于三方写一个清除图片缓存的机制。
经过考虑后想到了一条思路。使用 plist 存储相关图片信息,项目启动后开辟线程读取 plist 信息对并对超过七天的图片进行删除。(思路已定进行代码实现)
1、首先确认用 SD 来加载图片,在不动 SD 代码的基础上外部处理。找到 SD 缓存图片文件的文件夹,经过查找发现缓存图片都被存在沙盒中此路径下:Library/Caches/default/com.hackemist.SDWebImageCache.default,并且通过文件夹内图片的命名看出是通过 MD5 加密得到的。在查看 SD 原代码后进一步确认了命名规范(图片链接进行 MD5 加密)。这样就能准确的找到指定图片的本地缓存位置。
2、接下来对 SD 加载图片进行简单的封装,这样也符合高可维护性这一特点。创建一个 plist 文件以便于存储图片名称信息。在封装好的方法中,先调用自定义图片添加方法,按照 id 进行账号区分,在每个账号下创建新的字典,存储图片信息规则是:MD5 加密后的图片链接为 key,当前时间的时间戳为 value。按照 id 和 key 取出对应的时间戳 value 值 ,判断 value 是否为空,为空则把图片链接及时间添加到字典下,不为空则不做处理。
//获取对应的 plist 地址
+ (NSString *)imgPatchStr {
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"imgsClear.plist"];
return path;
}
//将未添加的图片名称添加到img.plist中(创建异步线程,防止界面卡顿)
+ (void)addImgViewPlist:(NSString *)imgUrl {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//plist文件地址
NSString *path = [CYTextTool imgPatchStr];
//获取到 plist 文件内的内容
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
//判断是否存在对应的 plist 文件
if (!dictionary) {
//如果不存在创建一个 dictionary 便于写入
dictionary = [NSMutableDictionary dictionary];
}
//获取账号下的图片字典
NSMutableDictionary *idDic = dictionary[kSTU_ID];
if (!idDic) {
//如果不存在则进行创建
idDic = [NSMutableDictionary dictionary];
//将账号字典添加到主字典中
[dictionary setObject:idDic forKey:kSTU_ID];
}
//获取图片对应的时间戳
NSString *idStr = idDic[imgUrl];
if (idStr.length == 0) {
//如果时间戳不存在则表明没有存储该图片信息
[idDic setObject:[CYTextTool currentTimeStr] forKey:imgUrl];
//将图片信息写入 plist 文件中
[dictionary writeToFile:path atomically:YES];
}
});
}
//MD5加密 小写32位 用于对图片名称进行加密
+ (NSString *)strWithMD5:(NSString *)str {
//要进行UTF8的转码
const char* input = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input, (CC_LONG)strlen(input), result);
NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[digest appendFormat:@"%02x", result[i]];
}
return digest;
}
3、当 app 启动并到首页后,调用图片查询方法。通过遍历的方式找到7天以外的所有图片名称,按照名称删除掉沙盒中对应的图片。当用户手动清空缓存时,对指定 id 的图片字典进行删除。
//清理过期图片(创建异步线程,防止界面卡顿)
+ (void)clearWithOverduePictures {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//自定义的 plist 文件,文件路径抽到了文本处理类中
NSString *path = [CYTextTool imgPatchStr];
//获取到 plist 文件内的内容
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
//按照对应的 id 找到该账号下的文件(kSTU_ID 获取当前用户 id 的宏)
NSMutableDictionary *idDic = dictionary[kSTU_ID];
//获取当前时间的时间戳
CGFloat timeNow = [[CYTextTool currentTimeStr] floatValue];
//创建图片数组便于添加需要删除的图片
NSMutableArray *imgArray = [NSMutableArray array];
//判断是否存在该账号的图片信息
if (idDic) {
//遍历字典找到每个图片的时间
for (NSString *key in idDic) {
//后去图片时间戳并与当前时间进行对比(时间戳是毫秒值)
CGFloat time = [idDic[key] floatValue];
if (time < (timeNow - 7 * 24 * 3600 * 1000)) {
[imgArray addObject:key];
}
}
}
if (imgArray.count != 0) {
//文件操作对象
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *imgPath = [NSString stringWithFormat:@"%@%@", cachePath, @"/default/com.hackemist.SDWebImageCache.default"];
//获取当前位置图片数组
NSArray *filesNameArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:imgPath error:nil];
//判断图片缓存位置存在图片后再进行操作
if (filesNameArray && filesNameArray.count != 0) {
for (NSString *imgUrl in imgArray) {
//删除缓存中的图片,图片名要拼接上图片类型,我们的图片是jpg的
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@.jpg", imgPath, imgUrl] error:nil];
//将应该删除的图片从列表中删除
[idDic removeObjectForKey:imgUrl];
}
}
}
//将新的字典更新到plist中
[dictionary writeToFile:path atomically:YES];
});
}
//删除图片分组(用户手动清理是可用)
+ (void)deleteAllImgPlist {
NSString *path = [CYTextTool imgPatchStr];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:path];
//将该账号下的图片信息删除
[dictionary removeObjectForKey:kSTU_ID];
//更新图片到 plist 中
[dictionary writeToFile:path atomically:YES];
}
//获取当前时间的时间戳
+ (NSString *)currentTimeStr {
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
NSTimeInterval time = [date timeIntervalSince1970] * 1000;
NSString *timeString = [NSString stringWithFormat:@"%.0f", time];
//将时间转化成字符串的形式进行输出
return timeString;
}
本人写的不好,只为做相关功能的小伙伴提供一点思路。谢谢!
网友评论