@WilliamAlex : 本章重点是如何在第三方框架自己的方法去实现我们想要的效果,同时要学会怎样使用工具类和封装代码.
关于"清除缓存",几乎在每一个App上都能在设置界面看到清除缓存这个功能,对于我这种初学者来说,刚开始很难理解缓存这个概念,所以,我决定将它做成一个版块,方便那些和我一样刚涉猎iOS的朋友理解,以下内容全是自己整理的笔记,如有不对之处,请大神们不吝赐教.
1, 整体思路:
1,首先,需要在根控制器中设置导航条右边的"设置"按钮
2, 由于前面我已经将设置导航条上的内容直接抽取到下面这个方法中了,所以在给"设置"按钮背景图片的同时,我就监听了"设置"按钮的点击.
3, 点击设置按钮之后跳转到设置界面,所以,需要新建一个继承于UITableViewController的类,在该类中设置"清除缓存".
-
4, 理清思路,搭建基本界面
- 4.1,当点击设置界面中的"清除缓存"对应的cell时,将下载的图片缓存全部从沙盒中清除掉.
- 4.2, 注意几个关键词:1, 点击cell时清除缓存. 2, 设置"清除缓存"在tableView中的位置. 3, 显示沙盒中有多大的缓存值.根据上面的关键词,运用对应的方法来做"清除缓存"操作.
5, 我们既然是从沙盒中获取缓存值,那么我就需要拿到对应沙盒的路径,根据路径获取对应目录下缓存文件,然后将之清除,做到这这里,我们可以将获取沙盒路径,删除缓存文件等相关操作都封装到一个继承自NSObject的工具类中.
2, 具体步骤
- 2.1, 在"我"这个根控制器设置监听按钮的点击,然后跳转到"设置"界面.
在WGMeViewController.m文件中
#import "WGMeViewController.h"
#import "WGSettingViewController.h"
@interface WGMeViewController ()
@end
@implementation WGMeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置标题
self.navigationItem.title = @"我的";
// 设置按钮
UIBarButtonItem *settingButton = [UIBarButtonItem barButtonWithImage:@"mine-setting-icon" hightLightImage:@"mine-setting-icon-click" target:self action:@selector(settingButtonClick)];
// 夜间模式按钮
UIBarButtonItem *nightMoonButton = [UIBarButtonItem barButtonWithImage:@"mine-moon-icon" hightLightImage:@"mine-moon-icon-click" target:self action:@selector(nightMoonButtonClick)];
// 将两个按钮添加到数组中
self.navigationItem.rightBarButtonItems = @[settingButton,nightMoonButton];
}
}
// 知识拓展: 我的习惯是将这样类似的方法抽取成一个分类,可以提高代码的复用性
// 监听导航条上的右边按钮的点击
- (void)settingButtonClick {
WGSettingViewController *settingVc = [[WGSettingViewController alloc] init];
[self.navigationController pushViewController:settingVc animated:YES];
}
- 2.2, 新建WGSettingViewController类
- 2.2.1, 这里需要注释一下: 既然我们最终的目的是获取到沙盒中缓存,将之清除掉.但是,我们该怎么获取到沙盒中的缓存内存呢?
在实际开发中我们大多数都是使用第三框架,因为它们大大提高了我们的工作效率,一般这样的框架都是有自己的方法获取到内存缓存,比如:在这个例子中我就使用了"SDWebImage"这个框架,我的习惯就是去看它的头文件有没有关于内存相关的关键词,如果有,那么直接点进去查看,内部有没有相关的属性或者方法拿到我们想要拿到的内存缓存. - 2.2.1.1, 在pods管理第三方框架的仓库中直接看到和内存相关的头文件,点进去查看方法或者属性:刚好有一个获取缓存的大小的属性getSize,
- 2.2.2, 拿到属性怎么用呢? 继续在头文件中找方法,你会发现框架内部有一个和内存有关的单例
SDImageCache框架中的缓存相关的方法
+ (SDImageCache *)sharedImageCache {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
// 这样就已经很明了了通过调用单例的getSize属性来获取内存缓存.
NSInteger cacheSize = [[SDImageCache shareImageCache].getSize];
// 注意:这个方法虽然简单,但是对初学者来说,一定要养成这样的习惯,不要依赖于教学视频(效率不高,实在不懂了,实在没办法了才去看看相关教程)
3, 知识拓展:
- 2.2.3, 这里需要拓展一下存储相关的知识.在开发的过程中,我们常常会和沙盒打交道,所以我们需要深刻了解沙盒的相关知识
- 1, Documents:程序运行时,产生的一些持久化的数据.iTunes同步时,会自动备份该目录下的所有文件.比如说:游戏应用就可以存档于该目录下
- 2, tmp: 保存一些应用在运行时所需要的"临时文件"使用完毕之后,会将相应的文件删除掉,甚至在程序没有运行时会自动清除该目录下的所有文件.最重要的一点"itunes不会同步该目录下的文件"
- 3, Library/Caches: 保存应用运行时生成的一些持久化数据,"iTunes不会同步该目录下的文件".一般存储体积比较大,存储一些不是很重要的数据
- 4, Library/Preference: 保存应用所有的偏好设置,iOS的settings(设置)应用会在该目录下找到对应的信息,"iTunes会同步设备时,会备份该目录".
4, 获取应用沙盒路径的几个常见方式:
// 沙盒的根目录:
NSString *home = NSHomeDirectory();
Documents:
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) [0];
// tmp: 临时文件
NSString *tmp = NSTemporaryDirectory();
// Library/Caches:跟Documents类似的两种方法,注意下面这个方法的第一个参数,参数不一样,获取的路径就不一样,并且获取到的路径不是全路径.
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) [0];
// Library/Preference: 通过NSUserDefaults类存取该目录下的设置信息.
if (![[NSUserDefaults standardUserDefaults] valueForKey:@"isFirst"]) {
AppGuidViewController *appGuid = [[AppGuidViewController alloc] initWithImageArray:@[@"guies01",@"guies02",@"guies03"]
startBtnDistanceWithBottomArray:@[@70,@100,@110,@120] needLoadVC:self.viewController];
self.window.rootViewController = appGuid; [[NSUserDefaults standardUserDefaults] setValue:@"YES" forKey:@"isFirst"];
} else
{
self.window.rootViewController = self.viewController;
}
5, 新建一个工具类:WGFileManagerTool
// 在WGFileManagerTool.h文件中
// 通过文件路径获取到目录文件下的所有文件的大小
+ (NSInteger)getCacheSizeOfDirectoriesPath:(NSString *)directoriesPath;
// 通过文件路径删除目录下所有缓存文件
+ (void)removeDirectoriesPath:(NSString *)directoriesPath;
// 在WGFileManagerTool.m文件中
// 业务类:专门处理某个业务,网络请求类,处理文件缓存
// 如何获取文件尺寸,遍历文件夹下所有文件,全部加起来.
// 获取文件夹尺寸,首先需要清除自己是使用的什么下载的图片,我们一般都是
// 使用一些比较便利的第三方框架,这里使用的是SDWebImage框架,所以需要我会
// 去头文件中,看看有没有获取缓存的方法,注意在获取缓存大小时,有很多细节需要弄清楚,
// 比如:attributesOfItemAtPath只对文件有效,对文件夹无效,所以我们都是要对传进来
// 的路径拼接和判断,是否存在,是否路径是文件夹等等细节问题.如果判断出来的值
// 不对或者说不存在,那么,就需要抛出异常
+ (NSInteger)getCacheSizeOfDirectoriesPath:(NSString *)directoriesPath
{
// 创建文件管理者(它是一个单例)
NSFileManager *manager = [NSFileManager defaultManager];
// 判断当前目录是否是文件夹或者是否存在
BOOL isDirectory;
/**
* 参数1: 传进来的路径directoriesPath
* 参数2: 是否是文件夹夹,注意这里的Bool值后面是一个"*",所以这里要传地址
*/
BOOL isExist = [manager fileExistsAtPath:directoriesPath isDirectory:&isDirectory];
// 判断传进来的路径对应的是否是文件夹或者是否存在,如果不存在或者不是,那么抛出异常
if (!isDirectory || !isExist) {
// 抛出异常
NSException *exception = [NSException exceptionWithName:@"文件路径不对" reason:@"请重新传入一个正确的路径" userInfo:nil];
[exception raise];
}
// 指定一个文件夹路径,获取这个文件夹路径目录里的所有子路径
NSArray *subPaths = [manager subpathsAtPath:directoriesPath];
// 遍历所有子路径,然后拼接拿到全路径后,通过全路径,拿到内存缓存,将通过子路径拿到的缓存相加起来就是我们最后要删除的缓存.
NSInteger totalCacheSize = 0;
for (NSString *subPath in subPaths) {
// 拼接全路径
NSString *fullFilePath = [directoriesPath stringByAppendingPathComponent:subPath];
// 判断当前的全路径是否是隐藏文件,或者不存在甚至是文件夹
BOOL isDirectory;
BOOL isExist = [manager fileExistsAtPath:fullFilePath isDirectory:&isDirectory];
if ([fullFilePath containsString:@"DS"] || !isExist || isDirectory) continue;
// 来到这里,表示它不是隐藏文件,存在以及不是文件夹
// 拿到文件属性
NSDictionary *attribute = [manager attributesOfItemAtPath:fullFilePath error:nil];
// 获取每个子路径的内存缓存
NSInteger cacheSize = [attribute[NSFileSize] integerValue];
totalCacheSize += cacheSize;
}
return totalCacheSize;
}
注意:
- 上面我是讲获取沙盒路径的方法封装到了一个工具类中.
- 我们只需要在外界调用这个方法,传进来一个路径即可.
6, WGSettingViewController类中
#import "WGSettingViewController.h"
#import "WGToolFileManager.h"
#import <SVProgressHUD.h>
#import <SDImageCache.h>
static NSString * const ID = @"cache";
@interface WGSettingViewController ()
/** 缓存值大小 */
@property (nonatomic, assign) CGFloat totalCacheSize;
@end
@implementation WGSettingViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化设置界面
[self initSettingViewController];
}
7, 初始化WGSettingViewController
#pragma mark - 初始化设置界面
- (void)initSettingViewController {
self.navigationItem.title = @"设置";
self.view.backgroundColor = WGRGBColor(239, 239, 239);
// 注册
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
[SVProgressHUD showWithStatus:@"正在计算缓存尺寸"];
// 获取缓存路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 计算内存缓存
[WGToolFileManager getCacheSizeOfDirectoriesPath:cachePath completeBlock:^(CGFloat totalCacheSize) {
_totalCacheSize = totalCacheSize;
[self.tableView reloadData];
[SVProgressHUD dismiss];
}];
}
8, 数据源方法(用于显示"清除缓存")
#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text = [self cacheStr:_totalCacheSize];
return cell;
}
9, 实现tableView的代理方法(点击cell,清除缓存)
#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 获取缓存路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 删除缓存
[WGToolFileManager removeCacheSizeOfDirectoriesPath:cachePath];
_totalCacheSize = 0;
// 刷新表格
[self.tableView reloadData];
}
10, 获取缓存字符串
// 获取缓存字符串
- (NSString *)cacheStr:(NSInteger)totalSize
{
// 获取文件夹缓存尺寸:文件夹比较小,文件夹非常大,获取尺寸比较耗时
CGFloat cacheSizeF = 0;
NSString *cacheStr = @"清空缓存";
if (totalSize > (1000 * 1000)) { //MB
cacheSizeF = totalSize / (1000 * 1000);
cacheStr = [NSString stringWithFormat:@"清空缓存(%.1fMB)",cacheSizeF];
cacheStr = [cacheStr stringByReplacingOccurrencesOfString:@".0" withString:@""];
} else if (totalSize > 1000) { //KB
cacheSizeF = totalSize / 1000;
cacheStr = [NSString stringWithFormat:@"清空缓存(%.1fKB)",cacheSizeF];
} else if (totalSize > 0){ // B
cacheStr = [NSString stringWithFormat:@"清空缓存(%ldB)",totalSize];
}
return cacheStr;
}