一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
YYCache
日常开发中,用到文件缓存必不可少,YYCache一款曾今风靡iOS圈的框架,简单易用且性能高效,磁盘缓存或内存缓存均支持,虽然是一款很老的框架,但依然是OC项目的首选。
实际项目使用时,我们可以将其二次封装成一个工具类使用,以下是项目中简单缓存音乐的例子。
@interface CCacheTool ()
@property (nonatomic, strong, readonly) YYCache *musicCache; ///< 音乐缓存管理
@end
@implementation CCacheTool
+ (instancetype)share {
static CCacheTool *tool = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
tool = [[CCacheTool alloc] init];
[tool.musicCache.memoryCache setCountLimit:0]; //内存最大缓存数据个数,因为是音乐大文件,不需要内存缓存
[tool.musicCache.diskCache setCountLimit:20]; //磁盘最大缓存数据个数
[tool.musicCache.diskCache setCostLimit:1000000*100]; //磁盘最大缓存数据个数
[tool.musicCache.diskCache setAutoTrimInterval:60]; //设置磁盘lru动态清理频率
});
return tool;
}
- (instancetype)init {
self = [super init];
if (self) {
_musicCache = [YYCache cacheWithName:@"MusicCache"];
_musicCache.diskCache.customFileNameBlock = ^NSString * _Nonnull(NSString * _Nonnull key) {
return [NSString stringWithFormat:@"%@.mp3",key];
};
return self;
}
- 可以使用customFileNameBlock自定义存储key,默认将以md5命名
缓存大小查询
- 获取磁盘缓存大小diskCache.totalCost
- 获取磁盘缓存数量diskCache.totalCount
- 获取内存缓存数量memoryCache.totalCount
- 获取内存缓存数量memoryCache.totalCount
_musicCache.diskCache.totalCost;
_musicCache.diskCache.totalCount;
_musicCache.memoryCache.totalCost;
_musicCache.memoryCache.totalCount;
增删改查的一些方法
- 封装均采用不阻塞线程带block的方法,对应还有不带block的方法,会阻塞当前线程,直到存取完成
- 获取文件路径的方法没有,自己看源码简单写了一个
// 存音乐文件,不会阻塞当前线程,操作完成后回调
- (void)saveMusicFile:(id)file forKey:(NSString *)key withBlock:(void(^)(void))block {
[_musicCache setObject:file forKey:key withBlock:block];
}
// 取音乐文件,不会阻塞当前线程,操作完成后回调
- (void)getMusicFileForKey:(NSString *)key withBlock:(void(^)(NSString *key, id<NSCoding> object))block {
[_musicCache objectForKey:key withBlock:block];
}
// 判断是否存在这个key
- (void)containsMusicForKey:(NSString *)key withBlock:(void (^)(NSString *key, BOOL contains))block {
[_musicCache containsObjectForKey:key withBlock:block];
}
// 根据key获取文件路径
- (NSString *)getMusicFilePathWithKey:(NSString *)key {
dispatch_semaphore_t _lock = [_musicCache.diskCache valueForKey:@"_lock"];
YYKVStorage *_kv = [_musicCache.diskCache valueForKey:@"_kv"];
if (!_kv) return nil;
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
YYKVStorageItem *item = [_kv getItemForKey:key];
dispatch_semaphore_signal(_lock);
NSString *filePath = [NSString stringWithFormat:@"%@/%@",[self musicFilePath],item.filename];
return filePath;
}
// 删除音乐文件,不会阻塞当前线程,操作完成后回调
- (void)removeMusicFileForKey:(NSString *)key withBlock:(void(^)(NSString *key))block {
[_musicCache removeObjectForKey:key withBlock:block];
}
// 删除所有音乐文件,不会阻塞当前线程,操作完成后回调
- (void)removeAllMusicFilesWithBlock:(void(^)(void))block {
[_musicCache removeAllObjectsWithBlock:block];
}
// 音乐文件的存储路径
- (NSString *)musicFilePath {
return [NSString stringWithFormat:@"%@/data",_musicCache.diskCache.path];
}
// 获取所有音乐文件的key
- (NSArray<NSString *> *)musicAllKeys {
YYKVStorage *kv = [_musicCache.diskCache valueForKey:@"kv"];
if (!kv) return nil;
return [NSArray arrayWithArray:[kv _dbGetkeys]];
}
- 获取所有文件的key并没有给出方法,我们可以简单仿照源码写一个分类
@interface YYKVStorage (CQ)
- (NSMutableArray *)_dbGetkeys;
@end
#import "YYKVStorage+CQ.h"
#if __has_include(<sqlite3.h>)
#import <sqlite3.h>
#else
#import "sqlite3.h"
#endif
@implementation YYKVStorage (CQ)
- (NSMutableArray *)_dbGetkeys {
NSString *sql = @"select key from manifest where key is not null;";
if (![self respondsToSelector:@selector(_dbPrepareStmt:)]) return nil;
sqlite3_stmt *stmt = (__bridge sqlite3_stmt *)([self performSelector:@selector(_dbPrepareStmt:) withObject:sql]);
if (!stmt) return nil;
NSMutableArray *filenames = [NSMutableArray new];
do {
int result = sqlite3_step(stmt);
if (result == SQLITE_ROW) {
char *filename = (char *)sqlite3_column_text(stmt, 0);
if (filename && *filename != 0) {
NSString *name = [NSString stringWithUTF8String:filename];
if (name) [filenames addObject:name];
}
} else if (result == SQLITE_DONE) {
break;
} else {
if (self.errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d)", __FUNCTION__, __LINE__, result);
filenames = nil;
break;
}
} while (1);
return filenames;
}
@end