清除缓存笔记[pre-release]
iOS平台文件存储目录
以下仅为官方文档的简单翻译
虽然iOS与Mac OS存储目录结构上差不多,但是实际对app用户数据的组织操作上却有所不同,在此仅说明iOS平台。
iOS每一个app拥有自己独立的沙盒,里面包括app boundle,数据存储目录,及iCloud存储目录。
通常目录结构
AppName.app | 程序的boundle,包括app和所有用到的资源(nib,storyboard,图片等).此目录不可写入,仅可读访问参考。此目录不会被iTunes备份,但是会从app store上同步购买app项目 |
---|---|
Documents/ | 用户数据存储目录,用于app内用户共享。可以通过iTunes备份 |
Documents/Inbox | 此目录通过ifunbox没有发现。好像是说对外可访问的,比如邮件这种系统应用,它把相关此应用的附件存储在这里。这个目录只可读取或删除,不能进行写入操作。它也是被iTunes备份的 |
Library/ | 存储非用户数据或不公开的数据,其中除Caches文件夹不备份之外,其他都可通过iTunes备份.Caches仅为缓存数据以提高用户体验,里面存放可丢弃数据 |
Library/Preferences | 应用特定文件,不应该在此创建文件,可以通过NSUserDefaults 读写文件,iTunes备份 |
tmp/ | 存储临时数据,相比Caches,此目录数据不做持久化处理,当不使用时应该自行清楚掉。当应用不运行时,系统会清除掉此目录数据,iTunes对此目录不做备份 |
- 把用户数据放在
Documents/.
目录下,通常包括任何需要可以公开的文件,便于用户创建,修改,编辑等操作。对于画图应用,如创建图片文件。对于文本编辑应用,如文本文件。音视频应用,如下载的音频视频文件。 - 把应用相关的文件存储在
Library/Application support/
,此是自行创建的子目录了,一般包括应用运行文件,配置文件,还有一些数据文件都对其用户不公开的。 - 由于
Documents/
下的文件默认是会备份的,你可以通过-[NSURL setResourceValue:forKey:error:]
方法,传入keyNSURLIsExcludedFromBackupKey
对不做备份的数据进行标识。对于一些可再创建和下载的媒体数据应该标识,方便用户备份。 - 临时数据放在
tmp/
目录下,这些数据不需要持久化,且用完需要清除以便节省空间,虽然系统会周期清除这些目录。 - 存放缓存数据在
Library/Caches/
,此数据相比tmp/
是持久化的,但是应该有个持久化周期,或大小限制,且这些数据如果被系统删除掉也能够自行创建或下载。缓存仅为了提高应用性能,但是也不能因此而浪费太多空间。
如何做清除缓存
了解清楚iOS平台文件系统之后,对于缓存清除工作就会有思路了。
Caches
目录可以清除,在此目录下应该存放缓存数据,即使被丢弃了也可再创建,再下载的数据Documents/
目录下自行创建的目录,如果用于缓存也是可以清除的,但是需要用户自行负责创建清除API用于统一清除tmp/
临时文件存储应该自行清除,不应该放入清除工作内- 网络缓存
Library/Cookies
目录也是可以清除的,在此没有涉及网络缓存
这里还参考一篇清除缓存的文章
实际项目代码片段:
-(void)clearUpCaches
{
///Loading...
[self showHudWithAnimated:YES];
__weak typeof(self)weakSelf = self;
__block NSUInteger size = 0;
///Caches文件路径
NSString *CachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSString *mp4Path = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"Private Documents"];
NSString *DocPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
///GCD group
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) , ^{
size += [weakSelf clearDataFromDir:CachesPath itself:NO];
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
size += [weakSelf clearDataFromDir:mp4Path itself:YES];
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
size += [weakSelf clearDataFromDir:DocPath itself:NO];
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[weakSelf hidenHudWithAnimated];
///打印文件大小
GODebugLog(@"已清理缓存文件 %@",[weakSelf filesizeFromNum:size]);
}
清除缓存文件共用方法:
/**
* 删除目录文件
*
* @param dirRoot 目录路径
* @param itself 是否删除当前目录文件夹,如Caches为系统创建不可删除设NO,自行创建文件夹可以删除设YES
*
* @return 删除文件总大小
*/
-(NSUInteger)clearDataFromDir:(NSString *)dirRoot itself:(BOOL)itself
{
BOOL isDir;
NSError *error;
BOOL isOk;
NSUInteger size = 0;
NSFileManager *fileMng = [NSFileManager new];
if ([fileMng fileExistsAtPath:dirRoot isDirectory:&isDir] && isDir) {
///Caches文件内所有可见文件
NSArray *urls = [fileMng contentsOfDirectoryAtURL:[NSURL fileURLWithPath:dirRoot isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];
for (NSURL *url in urls) {
error = nil;
NSString *path ;
[url getResourceValue:&path forKey:NSURLPathKey error:nil];
///删除前先计算文件大小
NSUInteger tempsize = [self getSizeFromDir:path];
///删除文件或文件夹
isOk = [fileMng removeItemAtPath:path error:&error];
if (isOk && !error) {
///累计已经清除的文件大小
size += tempsize;
}
}
if (itself) {
error = nil;
///删除前先计算文件大小
NSUInteger tempsize = [self getSizeFromDir:dirRoot];
isOk = [fileMng removeItemAtPath:dirRoot error:&error];
if (isOk && !error) {
size += tempsize;
}
}
}
return size;
}
-(NSUInteger)getSizeFromDir:(NSString *)dirPath
{
NSUInteger size = 0;
BOOL isDir;
NSFileManager *fileMng = [NSFileManager new];
///文件夹
if ([fileMng fileExistsAtPath:dirPath isDirectory:&isDir] && isDir) {
NSDirectoryEnumerator *paths = [fileMng enumeratorAtPath:dirPath];
for (NSString *path in paths) {
NSString *fullPath = [dirPath stringByAppendingPathComponent:path];
NSDictionary *dic = [fileMng attributesOfItemAtPath:fullPath error:nil];
size += [dic fileSize];
}
}
else
{
///单个文件
NSDictionary *dic = [fileMng attributesOfItemAtPath:dirPath error:nil];
size += [dic fileSize];
}
return size;
}
///显示文件大小
-(NSString *)filesizeFromNum:(NSUInteger)num
{
NSString *size;
if (num>=1000) {
CGFloat f = num/1000.0;
size = [NSString stringWithFormat:@"%.1f KB",f];
if (f>=1000) {
f = f/1000;
size = [NSString stringWithFormat:@"%.1f MB",f];
if (f>=1000) {
f = f/1000;
size = [NSString stringWithFormat:@"%.1f GB",f];
}
}
}
else
{
size = [NSString stringWithFormat:@"%d B",num];
}
return size;
}