iOS SDWebImage 七天清理图片机制

因项目中涉及到大量的图片展示问题,当图片累计过多时缓存到本地的图片会比较占本地内存空间,影响用户体验,为了提高用户体验,经过讨论后决定添加七天自动清理缓存功能。项目的图片展示是使用的 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;
}

本人写的不好,只为做相关功能的小伙伴提供一点思路。谢谢!

你可能感兴趣的:(iOS SDWebImage 七天清理图片机制)