前言
iOS 由于沙盒机制,不同APP之间不能相互访问彼此的目录,所以iOS 没有像安卓那样有大量的第三方APP来帮我们删除Cache,这必须是每个APP各扫门前雪。作为一个为用户着想的developer,为自己的APP添加缓存清理功能是非常有必要的~
iOS的沙盒目录
清理缓存我们首先得知道缓存在哪!
iOS8之前的sandbox目录
先来了解每个文件夹的作用如下:
文件夹 | 存放内容 | 是否会被iTunes同步 |
---|---|---|
myAPP.app | 该目录包含了应用程序本身的数据,包括资源文件和可执行文件等。程序启动以后,会根据需要从该目录中动态加载代码或资源到内存,这里用到了lazy loading的思想。 | 否 |
Documents | 我们可以将应用程序的数据文件保存在该目录下。不过这些数据类型仅限于不可再生的数据,可再生的数据文件应该存放在Library/Cache目录下。 | 是 |
Library | 苹果建议用来存放默认设置或其它状态信息。 | 是,但是要除了Caches子目录外 |
Library/Caches | 主要是缓存文件,用户使用过程中缓存都可以保存在这个目录中。比如网络请求的数据。鉴于此,应用程序通常还需要负责删除这些文件。 | 否 |
Library/Preferences | 应用程序的偏好设置文件。我们使用NSUserDefaults写的设置数据都会保存到该目录下的一个plist文件中 | 是 |
temp | 各种临时文件,保存应用再次启动时不需要的文件。而且,当应用不再需要这些文件时应该主动将其删除,因为该目录下的东西随时有可能被系统清理掉,目前已知的一种可能清理的原因是系统磁盘存储空间不足的时候。 | 否 |
所以我们所谓的清理缓存就是要对 “Cache”文件夹 “动手动脚”!
iOS8之后沙盒路径的变化
Apple在iOS8中对数据(sandbox)和包(.app)都进行了分离,并且采用最新的沙盒机制。
- Legacy location:~/Library/Application Support/
- Legacy location:~/Library/Containers/
/Data/Library/Application Support/ /
其中
例如我用模拟器打印出如下的路径:
- .app:/Users/lz/Library/Developer/CoreSimulator/Devices/FFF8CF48-2B3A-488F-8FA9-A61D867FBD81/data/Containers/Bundle/Application/CDC5A46C-FF3C-436E-B8F9-0F823A12AE12/Fingertip.app
- sandbox:/Users/lz/Library/Developer/CoreSimulator/Devices/FFF8CF48-2B3A-488F-8FA9-A61D867FBD81/data/Containers/Data/Application/F60A5FC6-669B-41DA-A33D-90AF2FFF6C45
缓存清理
缓存清理说白了就要对 sandbox 底下的 caches 文件夹下的文件进行删除,当然你可以选择性的删除,保留一些没有比用进行的清除的文件,比如,用户的头像图片等等。
我们必须实例化一个 NSFileManager 来做文件操作:
1 | @property (strong, nonatomic) NSFileManager *fileManager; |
获取沙盒目录下的Caches目录
有以下两种方法:
NSHomeDirectory()
1 | NSString *cacheFilePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; |
NSSearchPathForDirectoriesInDomains
1 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); |
计算缓存大小
1 | - (void)getCacheSize:(void (^)(NSString *size))completion |
说明:由于我们删除 caches 我文件夹底下的文件之后,可能系统会自动生成一些文件,导致缓存计算不为0;我们可以将小于 0.1M 的缓存视为 0M;防止“有强迫症”用户重复点击。
删除Caches文件夹下文件
这里为了有更好的用户体验使用了 MBProgressHUD,相信大家也不陌生。
具体代码如下:
1 | - (void)cleanCache:(void(^)(void))completion |
说明:如果是使用模拟器,我们我可以直接使用一下代码:
1 | if ([_fileManager fileExistsAtPath:_cacheFilePath]) { |
不需要去遍历文件夹判断是文件路径还是文件夹路径,再去删除。真机上是必须这样做的,因为真机运行代码时,是没有权限对文件夹做整一个的删除操作的。
代码地址
具体可以看我写的demo。
最后的话
最近感觉要学习的东西,太多太多了,博客会慢慢更,书会继续读,代码会努力打。