@WilliamAlex : 本章重點是如何在第三方框架自己的方法去實現(xiàn)我們想要的效果,同時要學(xué)會怎樣使用工具類和封裝代碼.
關(guān)于"清除緩存",幾乎在每一個App上都能在設(shè)置界面看到清除緩存這個功能,對于我這種初學(xué)者來說,剛開始很難理解緩存這個概念,所以,我決定將它做成一個版塊,方便那些和我一樣剛涉獵iOS的朋友理解,以下內(nèi)容全是自己整理的筆記,如有不對之處,請大神們不吝賜教.
1, 整體思路:
1,首先,需要在根控制器中設(shè)置導(dǎo)航條右邊的"設(shè)置"按鈕
2, 由于前面我已經(jīng)將設(shè)置導(dǎo)航條上的內(nèi)容直接抽取到下面這個方法中了,所以在給"設(shè)置"按鈕背景圖片的同時,我就監(jiān)聽了"設(shè)置"按鈕的點擊.
3, 點擊設(shè)置按鈕之后跳轉(zhuǎn)到設(shè)置界面,所以,需要新建一個繼承于UITableViewController的類,在該類中設(shè)置"清除緩存".
-
4, 理清思路,搭建基本界面
- 4.1,當(dāng)點擊設(shè)置界面中的"清除緩存"對應(yīng)的cell時,將下載的圖片緩存全部從沙盒中清除掉.
- 4.2, 注意幾個關(guān)鍵詞:1, 點擊cell時清除緩存. 2, 設(shè)置"清除緩存"在tableView中的位置. 3, 顯示沙盒中有多大的緩存值.根據(jù)上面的關(guān)鍵詞,運(yùn)用對應(yīng)的方法來做"清除緩存"操作.
5, 我們既然是從沙盒中獲取緩存值,那么我就需要拿到對應(yīng)沙盒的路徑,根據(jù)路徑獲取對應(yīng)目錄下緩存文件,然后將之清除,做到這這里,我們可以將獲取沙盒路徑,刪除緩存文件等相關(guān)操作都封裝到一個繼承自NSObject的工具類中.
2, 具體步驟
- 2.1, 在"我"這個根控制器設(shè)置監(jiān)聽按鈕的點擊,然后跳轉(zhuǎn)到"設(shè)置"界面.
在WGMeViewController.m文件中
#import "WGMeViewController.h"
#import "WGSettingViewController.h"
@interface WGMeViewController ()
@end
@implementation WGMeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 設(shè)置標(biāo)題
self.navigationItem.title = @"我的";
// 設(shè)置按鈕
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)];
// 將兩個按鈕添加到數(shù)組中
self.navigationItem.rightBarButtonItems = @[settingButton,nightMoonButton];
}
}
// 知識拓展: 我的習(xí)慣是將這樣類似的方法抽取成一個分類,可以提高代碼的復(fù)用性
// 監(jiān)聽導(dǎo)航條上的右邊按鈕的點擊
- (void)settingButtonClick {
WGSettingViewController *settingVc = [[WGSettingViewController alloc] init];
[self.navigationController pushViewController:settingVc animated:YES];
}
- 2.2, 新建WGSettingViewController類
- 2.2.1, 這里需要注釋一下: 既然我們最終的目的是獲取到沙盒中緩存,將之清除掉.但是,我們該怎么獲取到沙盒中的緩存內(nèi)存呢?
在實際開發(fā)中我們大多數(shù)都是使用第三框架,因為它們大大提高了我們的工作效率,一般這樣的框架都是有自己的方法獲取到內(nèi)存緩存,比如:在這個例子中我就使用了"SDWebImage"這個框架,我的習(xí)慣就是去看它的頭文件有沒有關(guān)于內(nèi)存相關(guān)的關(guān)鍵詞,如果有,那么直接點進(jìn)去查看,內(nèi)部有沒有相關(guān)的屬性或者方法拿到我們想要拿到的內(nèi)存緩存. - 2.2.1.1, 在pods管理第三方框架的倉庫中直接看到和內(nèi)存相關(guān)的頭文件,點進(jìn)去查看方法或者屬性:剛好有一個獲取緩存的大小的屬性getSize,
- 2.2.2, 拿到屬性怎么用呢? 繼續(xù)在頭文件中找方法,你會發(fā)現(xiàn)框架內(nèi)部有一個和內(nèi)存有關(guān)的單例
SDImageCache框架中的緩存相關(guān)的方法
+ (SDImageCache *)sharedImageCache {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
// 這樣就已經(jīng)很明了了通過調(diào)用單例的getSize屬性來獲取內(nèi)存緩存.
NSInteger cacheSize = [[SDImageCache shareImageCache].getSize];
// 注意:這個方法雖然簡單,但是對初學(xué)者來說,一定要養(yǎng)成這樣的習(xí)慣,不要依賴于教學(xué)視頻(效率不高,實在不懂了,實在沒辦法了才去看看相關(guān)教程)
3, 知識拓展:
- 2.2.3, 這里需要拓展一下存儲相關(guān)的知識.在開發(fā)的過程中,我們常常會和沙盒打交道,所以我們需要深刻了解沙盒的相關(guān)知識
- 1, Documents:程序運(yùn)行時,產(chǎn)生的一些持久化的數(shù)據(jù).iTunes同步時,會自動備份該目錄下的所有文件.比如說:游戲應(yīng)用就可以存檔于該目錄下
- 2, tmp: 保存一些應(yīng)用在運(yùn)行時所需要的"臨時文件"使用完畢之后,會將相應(yīng)的文件刪除掉,甚至在程序沒有運(yùn)行時會自動清除該目錄下的所有文件.最重要的一點"itunes不會同步該目錄下的文件"
- 3, Library/Caches: 保存應(yīng)用運(yùn)行時生成的一些持久化數(shù)據(jù),"iTunes不會同步該目錄下的文件".一般存儲體積比較大,存儲一些不是很重要的數(shù)據(jù)
- 4, Library/Preference: 保存應(yīng)用所有的偏好設(shè)置,iOS的settings(設(shè)置)應(yīng)用會在該目錄下找到對應(yīng)的信息,"iTunes會同步設(shè)備時,會備份該目錄".
4, 獲取應(yīng)用沙盒路徑的幾個常見方式:
// 沙盒的根目錄:
NSString *home = NSHomeDirectory();
Documents:
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) [0];
// tmp: 臨時文件
NSString *tmp = NSTemporaryDirectory();
// Library/Caches:跟Documents類似的兩種方法,注意下面這個方法的第一個參數(shù),參數(shù)不一樣,獲取的路徑就不一樣,并且獲取到的路徑不是全路徑.
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) [0];
// Library/Preference: 通過NSUserDefaults類存取該目錄下的設(shè)置信息.
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文件中
// 業(yè)務(wù)類:專門處理某個業(yè)務(wù),網(wǎng)絡(luò)請求類,處理文件緩存
// 如何獲取文件尺寸,遍歷文件夾下所有文件,全部加起來.
// 獲取文件夾尺寸,首先需要清除自己是使用的什么下載的圖片,我們一般都是
// 使用一些比較便利的第三方框架,這里使用的是SDWebImage框架,所以需要我會
// 去頭文件中,看看有沒有獲取緩存的方法,注意在獲取緩存大小時,有很多細(xì)節(jié)需要弄清楚,
// 比如:attributesOfItemAtPath只對文件有效,對文件夾無效,所以我們都是要對傳進(jìn)來
// 的路徑拼接和判斷,是否存在,是否路徑是文件夾等等細(xì)節(jié)問題.如果判斷出來的值
// 不對或者說不存在,那么,就需要拋出異常
+ (NSInteger)getCacheSizeOfDirectoriesPath:(NSString *)directoriesPath
{
// 創(chuàng)建文件管理者(它是一個單例)
NSFileManager *manager = [NSFileManager defaultManager];
// 判斷當(dāng)前目錄是否是文件夾或者是否存在
BOOL isDirectory;
/**
* 參數(shù)1: 傳進(jìn)來的路徑directoriesPath
* 參數(shù)2: 是否是文件夾夾,注意這里的Bool值后面是一個"*",所以這里要傳地址
*/
BOOL isExist = [manager fileExistsAtPath:directoriesPath isDirectory:&isDirectory];
// 判斷傳進(jìn)來的路徑對應(yīng)的是否是文件夾或者是否存在,如果不存在或者不是,那么拋出異常
if (!isDirectory || !isExist) {
// 拋出異常
NSException *exception = [NSException exceptionWithName:@"文件路徑不對" reason:@"請重新傳入一個正確的路徑" userInfo:nil];
[exception raise];
}
// 指定一個文件夾路徑,獲取這個文件夾路徑目錄里的所有子路徑
NSArray *subPaths = [manager subpathsAtPath:directoriesPath];
// 遍歷所有子路徑,然后拼接拿到全路徑后,通過全路徑,拿到內(nèi)存緩存,將通過子路徑拿到的緩存相加起來就是我們最后要刪除的緩存.
NSInteger totalCacheSize = 0;
for (NSString *subPath in subPaths) {
// 拼接全路徑
NSString *fullFilePath = [directoriesPath stringByAppendingPathComponent:subPath];
// 判斷當(dāng)前的全路徑是否是隱藏文件,或者不存在甚至是文件夾
BOOL isDirectory;
BOOL isExist = [manager fileExistsAtPath:fullFilePath isDirectory:&isDirectory];
if ([fullFilePath containsString:@"DS"] || !isExist || isDirectory) continue;
// 來到這里,表示它不是隱藏文件,存在以及不是文件夾
// 拿到文件屬性
NSDictionary *attribute = [manager attributesOfItemAtPath:fullFilePath error:nil];
// 獲取每個子路徑的內(nèi)存緩存
NSInteger cacheSize = [attribute[NSFileSize] integerValue];
totalCacheSize += cacheSize;
}
return totalCacheSize;
}
注意:
- 上面我是講獲取沙盒路徑的方法封裝到了一個工具類中.
- 我們只需要在外界調(diào)用這個方法,傳進(jìn)來一個路徑即可.
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];
// 初始化設(shè)置界面
[self initSettingViewController];
}
7, 初始化WGSettingViewController
#pragma mark - 初始化設(shè)置界面
- (void)initSettingViewController {
self.navigationItem.title = @"設(shè)置";
self.view.backgroundColor = WGRGBColor(239, 239, 239);
// 注冊
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
[SVProgressHUD showWithStatus:@"正在計算緩存尺寸"];
// 獲取緩存路徑
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 計算內(nèi)存緩存
[WGToolFileManager getCacheSizeOfDirectoriesPath:cachePath completeBlock:^(CGFloat totalCacheSize) {
_totalCacheSize = totalCacheSize;
[self.tableView reloadData];
[SVProgressHUD dismiss];
}];
}
8, 數(shù)據(jù)源方法(用于顯示"清除緩存")
#pragma mark - 數(shù)據(jù)源方法
- (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, 實現(xiàn)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;
}