第三天任務(wù):
今天主要任務(wù)完成我的模塊的搭建。
- 我的頁(yè)面的搭建
- 清除緩存功能
- 方法抽取總結(jié)
我的頁(yè)面的搭建
我們先來(lái)看一下我的界面內(nèi)容
通過(guò)上面圖片可以看出,我的界面是一個(gè)非常簡(jiǎn)單的tableView,上面兩個(gè)cell只需要簡(jiǎn)單設(shè)置圖片,文字和最右邊箭頭就可以了,主要是最下面方塊view的顯示。這里我們有兩種解決方案
一:可以是一個(gè)cell,如果最后一個(gè)是一個(gè)cell,稍微有些麻煩,因?yàn)樽詈笠粋€(gè)cell比較特殊,需要與前兩個(gè)cell區(qū)分,沒(méi)有辦法統(tǒng)一設(shè)置。
二:可以是一個(gè)tablefootView,這種方法比較簡(jiǎn)單,我們直接自定義view顯示自己想要顯示的內(nèi)容,然后添加到tablefootView上面就可以了。
創(chuàng)建自定義view CLMeFooterView。首先分析,CLMeFooterView需要有哪些功能
- 請(qǐng)求數(shù)據(jù),本著面向?qū)ο螅l(shuí)的任務(wù)誰(shuí)來(lái)負(fù)責(zé)的基本原則,我們將數(shù)據(jù)請(qǐng)求寫(xiě)在CLMeFooterView中
- 布局子控件,CLMeFooterView只管布局子控件和添加點(diǎn)擊事件即可,至于子控件中的內(nèi)容和字體大小顏色等等,都讓子控件自己去管理,另外CLMeFooterView的寬度是固定的但是需要根據(jù)子控件的多少來(lái)設(shè)置自己的長(zhǎng)度。
- 點(diǎn)擊事件的實(shí)現(xiàn),需要根據(jù)模型參數(shù)的不同,判斷是調(diào)到其他界面還是進(jìn)行http請(qǐng)求
我們通過(guò)重寫(xiě)CLMeFooterView的initWithFrame方法,在initWithFrame方法中請(qǐng)求數(shù)據(jù)和布局子控件。
代碼中使用AFN來(lái)請(qǐng)求數(shù)據(jù),使用MJExtension對(duì)數(shù)據(jù)進(jìn)行對(duì)模型的轉(zhuǎn)換。在請(qǐng)求數(shù)據(jù)時(shí),可以現(xiàn)在請(qǐng)求成功之后,將服務(wù)器返回的數(shù)據(jù)寫(xiě)到plist文件中存放到桌面,這樣便于我們對(duì)返回?cái)?shù)據(jù)層次結(jié)構(gòu)的理解和里面數(shù)據(jù)的查閱
// 寫(xiě)出plist文件到桌面 便于我們看
// [responseObject writeToFile:@"/Users/yangboxing/Desktop/me.plist" atomically:YES];
查看寫(xiě)在桌面的plist文件,
通過(guò)觀察我們發(fā)現(xiàn)square_list中我們只需要用到icon , name ,url,三個(gè)屬性就可以了其他的屬性并不用到,也就沒(méi)有必要去浪費(fèi)內(nèi)存存儲(chǔ)用不到的數(shù)據(jù),據(jù)此創(chuàng)建CLMeSquare模型,至于數(shù)據(jù)轉(zhuǎn)模型MJExtension內(nèi)部已經(jīng)幫我們實(shí)現(xiàn)。
來(lái)看一下請(qǐng)求數(shù)據(jù)代碼
// 參數(shù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"square";
params[@"c"] = @"topic";
[[AFHTTPSessionManager manager]GET:@"http://api.budejie.com/api/api_open.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * _Nullable responseObject) {
// 將字典中square_list對(duì)應(yīng)的數(shù)據(jù)轉(zhuǎn)化為模型數(shù)組
NSArray *squares = [CLMeSquare mj_objectArrayWithKeyValuesArray:responseObject[@"square_list"]];
[self createSquare:squares];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
CLLog(@"請(qǐng)求失敗");
}];
關(guān)于AFN的使用請(qǐng)參考iOS-網(wǎng)絡(luò)編程(三)AFNetworking使用
而MJExtension內(nèi)部通過(guò)RunTime來(lái)進(jìn)行字典轉(zhuǎn)模型,與KVC不同的是,RunTime字典轉(zhuǎn)模型實(shí)現(xiàn)原理是遍歷模型中的所有屬性名,然后去字典查找,也就是以模型為準(zhǔn),模型中有哪些屬性,就去字典中找那些屬性。當(dāng)服務(wù)器返回的數(shù)據(jù)過(guò)多,而我們只使用其中很少一部分時(shí),沒(méi)有用的屬性就沒(méi)有必要定義成屬性了。
數(shù)據(jù)請(qǐng)求成功接下來(lái)就是子控件的布局,子控件的布局就是很簡(jiǎn)單的九宮格布局,需要注意的一點(diǎn)是,我們需要設(shè)置footView的高度就等于最后一個(gè)子控件的最大Y值,并且在tableView中,cell顯示完畢后,在最低端會(huì)多出20的距離。如下圖:
解決的方法非常簡(jiǎn)單,當(dāng)設(shè)置完footView的高度之后,拿到tableView重新刷新一下tableView就可以了
// 布局子控件
-(void)createSquare:(NSArray *)squares
{
NSUInteger count = squares.count;
int maxColsCount = 4;
CGFloat buttonW = self.cl_width / 4;
CGFloat buttonH = buttonW;
for (int i = 0; i < count; i ++) {
CLMeSquare *square = squares[i];
CLMeSquareButton *button =[CLMeSquareButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
// 設(shè)置button的模型屬性
button.square = square;
// 設(shè)置button的frame
button.cl_x = (i % maxColsCount) * buttonW;
button.cl_y = (i / maxColsCount) * buttonH;
button.cl_width = buttonW;
button.cl_height = buttonH;
button.backgroundColor = [UIColor whiteColor];
[self addSubview:button];
}
self.cl_height = self.subviews.lastObject.cl_bottom;
UITableView *tableView = (UITableView *)self.superview;
tableView.tableFooterView = self;
[tableView reloadData]; // 重新刷新數(shù)據(jù)也會(huì)重新計(jì)算 contentSize 就不會(huì)在最后在增加20了。
}
而子控件的內(nèi)容由子控件自己來(lái)設(shè)置,每一個(gè)子控件為正方形,可以顯示圖片文字,并且有點(diǎn)擊事件,所以子控件可以使用Button。
創(chuàng)建自定義控件CLMeSquareButton,重寫(xiě)layoutSubviews來(lái)布置button中imageView和titleLabel的位置
-(void)layoutSubviews
{
[super layoutSubviews];
// 修改button 內(nèi)imageView 和 label的位置
self.imageView.cl_y = self.cl_height * 0.15;
self.imageView.cl_width = self.cl_width * 0.5;
self.imageView.cl_height = self.imageView.cl_width;
self.imageView.cl_centerX = self.cl_width * 0.5;
self.titleLabel.cl_x = 0;
self.titleLabel.cl_y = self.imageView.cl_bottom;
self.titleLabel.cl_width = self.cl_width;
self.titleLabel.cl_height = self.cl_height - self.imageView.cl_bottom;
}
initWithFrame方法中設(shè)置button字體大小,顏色,居中,背景圖片等。
-(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.font = [UIFont systemFontOfSize:15];
[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
// 如果沒(méi)有提供圖片我們可以設(shè)置buton width height 分別減1;
[self setBackgroundImage:[UIImage imageNamed:@"mainCellBackground"] forState:UIControlStateNormal];
}
return self;
}
另外,因?yàn)辄c(diǎn)擊CLMeSquareButton,我們要拿到模型中的url,進(jìn)行跳轉(zhuǎn)或者h(yuǎn)ttp請(qǐng)求,所以給button添加一個(gè)CLMeSquare模型屬性,并且可以通過(guò)CLMeSquare的set方法來(lái)給CLMeSquareButton中imageView和titleLabel賦值
-(void)setSquare:(CLMeSquare *)square
{
// 通過(guò)bubtton 的屬性 square的set方法,拿到square后給button的圖片和文字賦值 。
_square = square;
// 設(shè)置所有button的圖片和文字
[self setTitle:square.name forState:UIControlStateNormal];
[self sd_setImageWithURL:[NSURL URLWithString:square.icon] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed:@"header_cry_icon"]];
}
最后就是按鈕點(diǎn)擊事件的實(shí)現(xiàn),需要對(duì)參數(shù)url進(jìn)行判斷,根據(jù)不同的url進(jìn)行不同的操作,如果是mod開(kāi)頭的就跳轉(zhuǎn)到其他界面,如果是http開(kāi)頭的就需要加載網(wǎng)頁(yè)。
- 對(duì)開(kāi)頭字母的判斷
// 判斷是否以http開(kāi)頭
[square.url hasPrefix:@"http"]
//延伸: [square.url hasSuffix:@"http"] 判斷是否以http結(jié)尾
- 如何加載webViewController,并跳轉(zhuǎn)到webViewController
加載webViewController很簡(jiǎn)單,創(chuàng)建webViewController并將url賦值給他即可。
CLWebViewController *webVc = [[CLWebViewController alloc]init];
webVc.url = square.url;
在自定義的footView中,跳轉(zhuǎn)到webViewController,首先需要拿到NavgationController通過(guò)push方法進(jìn)行跳轉(zhuǎn),如果想拿到NavgationController,需要拿到tabBarController,tabBarController的selectedViewController,即可拿到當(dāng)前選擇的NavgationController,而tabBarController我們可以通過(guò)窗口的跟控制器拿到。
UITabBarController *tabBarVC = (UITabBarController *)self.window.rootViewController;
UINavigationController *naVC = tabBarVC.selectedViewController;
webVc.navigationItem.title = square.name;
[naVC pushViewController:webVc animated:YES];
- 另外iOS9之后引入
#import <SafariServices/SafariServices.h>
可以使用系統(tǒng)的Safari來(lái)進(jìn)行網(wǎng)頁(yè)加載,并且功能非常齊全,可以前進(jìn),后退,刷新還可以顯示進(jìn)度條。但是注意:只有mode出來(lái)的Safari才會(huì)顯示進(jìn)度條等控件。
SFSafariViewController *webView = [[SFSafariViewController alloc]initWithURL:[NSURL URLWithString:square.url]];
UITabBarController *tabBarVC = (UITabBarController *)self.window.rootViewController;
[tabBarVC presentViewController:webView animated:YES completion:nil];
此時(shí),整個(gè)界面基本上已經(jīng)完成了,接下來(lái)完成點(diǎn)擊又上角設(shè)置按鈕,進(jìn)入設(shè)置界面,清除緩存功能。
清除緩存功能
首先來(lái)看一下設(shè)置界面
首先設(shè)置界面涉及到兩種不同類型cell共存的問(wèn)題,很明顯第一行清除緩存cell與下面的cell類型不同,如果所有cell放到同一個(gè)緩存池中,當(dāng)清除緩存cell復(fù)用到下面的cell時(shí),需要去掉右邊箭頭,當(dāng)清除緩存cell重新加載時(shí),又需要加上右邊箭頭,并且清除緩存內(nèi)部是需要做清除緩存功能的,而其他cell不需要這個(gè)功能,所以當(dāng)一個(gè)cell是特有的,與其他cell不一樣,業(yè)務(wù)邏輯也需要被獨(dú)立的封裝起來(lái),為了避免復(fù)雜重復(fù)的操作,這種cell最好獨(dú)立出來(lái),并且不要循環(huán)給別的cell。
我們通過(guò)使用兩種獨(dú)立類型的cell,使用不同的標(biāo)識(shí)來(lái)區(qū)分兩種cell,一種標(biāo)識(shí)就對(duì)應(yīng)一種cell 通過(guò)一種標(biāo)識(shí)來(lái)找一種cell的時(shí)候,如果沒(méi)有那么創(chuàng)建一個(gè)cell,通過(guò)另外一種標(biāo)識(shí)來(lái)找cell 的時(shí)候,就會(huì)創(chuàng)建另外一種cell,如果緩存池中有就去自己標(biāo)識(shí)的緩存池中取。
由此類推多種不同的cell,對(duì)應(yīng)多種不同的標(biāo)識(shí)。每種類型的cell,創(chuàng)建并緩存到自己對(duì)應(yīng)標(biāo)識(shí)的緩存池中。
這里設(shè)置界面自定義兩種cell,清除緩存的CLClearCacheCell,其他類型的CLSettingCell,兩種cell都需要進(jìn)行注冊(cè)
static NSString * const CLClearCacheCellId = @"CLClearCacheCell";
static NSString * const CLSettingCellId = @"CLSettingCellId";
// 注冊(cè)cell
[self.tableView registerClass:[CLClearCacheCell class] forCellReuseIdentifier:CLClearCacheCellId];
[self.tableView registerClass:[CLSettingCell class] forCellReuseIdentifier:CLSettingCellId];
當(dāng)使用時(shí),按照不同的行區(qū)分需要顯示的不同類型的cell
// 按照不同的標(biāo)識(shí) 重用不同的cell
// 取出cell,這里第0行是清除緩存cell,其他行是其他cell
if (indexPath.row == 0) {
CLClearCacheCell *cell = [tableView dequeueReusableCellWithIdentifier:CLClearCacheCellId];
return cell;
}else{
CLSettingCell *cell = [tableView dequeueReusableCellWithIdentifier:CLSettingCellId];
cell.textLabel.text = @"haha";
return cell;
}
另外,我們需要給CLClearCacheCell添加tap手勢(shì),確保緩存文件大小計(jì)算完畢之后,才可以點(diǎn)擊CLClearCacheCell清除緩存,當(dāng)給cell添加tap手勢(shì)之后,就會(huì)自動(dòng)覆蓋cell的代理方法tableView: didSelectRowAtIndexPath
。
接下來(lái)是將清除緩存業(yè)務(wù)邏輯封裝到CLClearCacheCell中,首先清除緩存是清除沙盒中Caches中的文件,并且通過(guò)代碼刪除是不可逆的。來(lái)看一下沙盒中Caches文件內(nèi)容
其中custom是我們自己創(chuàng)建的用來(lái)緩存的文件夾,default是SD創(chuàng)建的圖片緩存文件,我們需要將這兩個(gè)文件夾內(nèi)容大小計(jì)算出來(lái),計(jì)算文件夾的大小,本質(zhì)上就是遍歷文件夾里面所有文件并計(jì)算文件大小,最后累加計(jì)算出文件夾總的大小。之后就是清除緩存,清除緩存的本質(zhì)就是刪掉這兩個(gè)文件,并重新創(chuàng)建新的文件夾。
SD提供了計(jì)算dufault文件大小和刪除文件的方法。引入#import <SDImageCache.h>
// 獲取文件大小
[SDImageCache sharedImageCache].getSize
//
// clear清除所有圖片文件
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
// 清除之后要做的事兒
}];
// clearn 只清除時(shí)間超過(guò)一周的文件
[[SDImageCache sharedImageCache] cleanDiskWithCompletionBlock:^{
// 清除之后要做的事兒
}];
接下來(lái)我們要仿照SD清除緩存的內(nèi)部實(shí)現(xiàn)來(lái)做我們自己創(chuàng)建的文件custom的清除緩存功能。首先計(jì)算文件大小
// 總大小
unsigned long long size = 0;
// 獲取緩存文件路徑
NSString *cachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
// 拼接全文件路徑
NSString *filePath = [cachesPath stringByAppendingPathComponent:@"custom"];
// 創(chuàng)建文件管理者
NSFileManager *manager = [NSFileManager defaultManager];
// 使用遍歷器獲得custom文件下所有文件的子路徑
NSDirectoryEnumerator *enumerator = [manager enumeratorAtPath:filePath];
for (NSString *subpath in enumerator) {
// 拼接成完整路徑
NSString *fullParh = [filePath stringByAppendingPathComponent:subpath];
// 獲取文件屬性字典
NSDictionary *attribute = [manager attributesOfItemAtPath:fullParh error:nil];
// 累加文件大小
size += attribute.fileSize;
}
也可以通過(guò)獲得子路徑數(shù)組進(jìn)行遍歷
NSArray *subpaths = [manager subpathsAtPath:filePath];
for (NSString *subpath in subpaths) {
// 拼接成完整路徑
NSString *fullParh = [filePath stringByAppendingPathComponent:subpath];
// 獲取文件屬性字典
NSDictionary *attribute = [manager attributesOfItemAtPath:fullParh error:nil];
//size += [attribute[NSFileSize] unsignedIntegerValue];
// fileSize方法返回的就是 NSFileSize 對(duì)應(yīng)的key
//累加文件大小
size += attribute.fileSize;
}
刪除costum文件并重新創(chuàng)建空的文件夾
#define CLCustomCacheFile [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"custom"]
NSFileManager *manager = [NSFileManager defaultManager];
// 刪除文件
[manager removeItemAtPath:CLCustomCacheFile error:nil];
// 創(chuàng)建文件 withIntermediateDirectories:YES 表示如果沒(méi)有中間文件會(huì)自動(dòng)創(chuàng)建,NO 表示不會(huì)自動(dòng)創(chuàng)建中間文件,如果發(fā)現(xiàn)沒(méi)有文件則不會(huì)創(chuàng)建
[manager createDirectoryAtPath:CLCustomCacheFile withIntermediateDirectories:YES attributes:nil error:nil];
注意:計(jì)算文件大小和刪除文件并重新創(chuàng)建都數(shù)據(jù)耗時(shí)操作,要放到子線程中去執(zhí)行。
自定義CLClearCacheCell還有一些其他的邏輯需要注意。
- 等設(shè)置完文字之后在禁止cell點(diǎn)擊,如果直接禁止點(diǎn)擊,字體顏色會(huì)被渲染成灰色,文件大小計(jì)算完畢之后在開(kāi)啟點(diǎn)擊。
- 先顯示正在計(jì)算的小菊花,等計(jì)算完畢之后關(guān)閉小菊花,顯示箭頭,這里有一個(gè)注意點(diǎn),accessoryView比accessoryType優(yōu)先級(jí)要高,所以顯示箭頭的時(shí)候,需要先將accessoryView至為空然后在設(shè)置accessoryType。并且當(dāng)正在計(jì)算時(shí),將第一行cell滑出屏幕,在返回時(shí)發(fā)現(xiàn)小菊花已經(jīng)不在了,我們可以通過(guò)重寫(xiě)cell的layoutSubviews,重新設(shè)置cell小菊花start,因?yàn)槊慨?dāng)cell顯示的時(shí)候都會(huì)調(diào)用layoutSubviews方法。
- 計(jì)算文件大小,顯示在cell上,根據(jù)不同的大小顯示不同的單位GB,MB,KB等。
- 點(diǎn)擊cell清除緩存,可以先清除SD的圖片緩存,SD緩存清除完畢之后在,在開(kāi)子線程清除其他文件的緩存,之后在回到主線程刷新cell的內(nèi)容。
- cell的銷毀時(shí)刻,當(dāng)進(jìn)入設(shè)置控制器,正在計(jì)算文件大小時(shí),返回,此時(shí)設(shè)置控制器已經(jīng)被銷毀。但是cell會(huì)等子線程任務(wù)執(zhí)行完畢之后才會(huì)被銷毀,因?yàn)檫€要用到cell且block中強(qiáng)引用了strong的對(duì)象,所以不會(huì)讓cell銷毀。所以在block中使用弱引用,block內(nèi)部就不會(huì)對(duì)那個(gè)對(duì)象產(chǎn)生強(qiáng)引用。其該釋放的時(shí)候就會(huì)被釋放,雖然已經(jīng)釋放,但是代碼還是會(huì)往下面執(zhí)行,此時(shí)對(duì)象為空。
- 點(diǎn)擊清除按鈕的時(shí)候使用SVProgressHUD彈出提醒框,清除完畢之后關(guān)閉提醒框。
理解了這些來(lái)看一下CLClearCacheCell的代碼
#define CLCustomCacheFile [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"custom"]
@implementation CLClearCacheCell
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.textLabel.text = @"清除緩存(正在計(jì)算文件大小...)";
// 等設(shè)置完文字之后在禁止點(diǎn)擊,如果直接禁止點(diǎn)擊 字體顏色會(huì)被渲染成灰色
self.userInteractionEnabled = NO;
// 設(shè)置小菊花
UIActivityIndicatorView *indicatorView =[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[indicatorView startAnimating];
self.accessoryView = indicatorView;
// 創(chuàng)建弱引用對(duì)象
__weak typeof(self) weakSelf = self;
// 開(kāi)啟子線程計(jì)算文件大小
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// mac中換算MB 除以1000,并不是以1024為單位
// 總大小
unsigned long long size = 0;
NSArray *subpaths = [manager subpathsAtPath:CLCustomCacheFile];
for (NSString *subpath in subpaths) {
// 拼接成完整路徑
NSString *fullParh = [filePath stringByAppendingPathComponent:subpath];
// 獲取文件屬性字典
NSDictionary *attribute = [manager attributesOfItemAtPath:fullParh error:nil];
// 累加文件大小
size += attribute.fileSize;
}
size = size+ [SDImageCache sharedImageCache].getSize;
// 判斷cell是否已經(jīng)被銷毀,如果銷毀了就直接返回
if (weakSelf == nil) {
return ;
}
NSString *sizeText = nil;
if (size >= pow(10, 9)) {
sizeText = [NSString stringWithFormat:@"%.1fGB",size / 1000.0 / 1000.0 / 1000.0];
}else if (size >= pow(10, 6)){
sizeText = [NSString stringWithFormat:@"%.1fMB",size / 1000.0 / 1000.0];
}else if (size >= pow(10, 3)){
sizeText = [NSString stringWithFormat:@"%.1fKB",size / 1000.0];
}else{
sizeText = [NSString stringWithFormat:@"%zdB",size];
}
NSString *text = [NSString stringWithFormat:@"清除緩存(%@)",sizeText];
// 回到主線程刷新cell
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.textLabel.text = text;
weakSelf.accessoryView = nil;
weakSelf.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
weakSelf.userInteractionEnabled = YES;
// 等計(jì)算完緩存大小之后在添加手勢(shì),保證正在計(jì)算過(guò)程中cell 點(diǎn)擊無(wú)效
[weakSelf addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:weakSelf action:@selector(celltap:)]];
});
});
}
return self;
}
// cell點(diǎn)擊手勢(shì)
-(void)celltap:(UITapGestureRecognizer *)tap
{
[SVProgressHUD showWithStatus:@"正在清除緩存"];
// 清除所有圖片文件 clearn 只清除時(shí)間超過(guò)一周的文件
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
// 清除之后要做的事兒
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSFileManager *manager = [NSFileManager defaultManager];
[manager removeItemAtPath:CLCustomCacheFile error:nil];
//withIntermediateDirectories:YES ,表示中間文件如果沒(méi)有會(huì)自動(dòng)創(chuàng)建,NO 也不會(huì)自動(dòng)創(chuàng)建中間文件,如果發(fā)現(xiàn)沒(méi)有文件則不會(huì)創(chuàng)建
[manager createDirectoryAtPath:CLCustomCacheFile withIntermediateDirectories:YES attributes:nil error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
// 隱藏指示器
[SVProgressHUD dismiss];
self.textLabel.text = @"清除緩存(0B)";
});
});
}];
}
// 每當(dāng)cell 重新顯示在桌面上 ,都會(huì)調(diào)用laoutsubviews
-(void)layoutSubviews
{
[super layoutSubviews];
UIActivityIndicatorView *indicator = (UIActivityIndicatorView *)self.accessoryView;
[indicator startAnimating];
}
@end
方法抽取總結(jié)
獲取文件大小需要經(jīng)常用到的,可以通過(guò)給NSString添加分類方法將獲取文件大小的方法抽取出來(lái),使用文件路徑直接調(diào)用fileSize方法即可獲得文件大小。
NSString+CLExtension.h
#import <Foundation/Foundation.h>
@interface NSString (CLExtension)
-(unsigned long long)fileSize;
@end
NSString+CLExtension.m
#import "NSString+CLExtension.h"
@implementation NSString (CLExtension)
-(unsigned long long)fileSize
{
unsigned long long size = 0;
NSFileManager *manager = [NSFileManager defaultManager];
BOOL directory = NO;
BOOL exists = [manager fileExistsAtPath:self isDirectory:&directory];
// 如果地址為空
if (!exists) return size;
// 如果是文件夾
if (directory) {
NSDirectoryEnumerator *enumerator = [manager enumeratorAtPath:self];
for (NSString *path in enumerator) {
NSString *fullPath = [self stringByAppendingPathComponent:path];
NSDictionary *attr = [manager attributesOfItemAtPath:fullPath error:nil];
size += attr.fileSize;
}
}else{
size = [manager attributesOfItemAtPath:self error:nil].fileSize;
}
return size;
}
@end
這樣當(dāng)需要獲取文件大小的時(shí)候,直接使用路徑.fileSize
就可以獲得文件大小了,非常方便。并且這個(gè)方法在別的項(xiàng)目中也經(jīng)常會(huì)用到,快將這個(gè)方法添加到你的代碼庫(kù)中吧。
總結(jié)
今天主要完成了我的界面的搭建,主要內(nèi)容CocoaPods的使用以及AFN,SD,MJExtension等第三方框架的簡(jiǎn)單使用,tableView的footView的布局和顯示,webView的加載,多種cell共存的實(shí)現(xiàn),清除緩存功能的實(shí)現(xiàn)等,其中有許多細(xì)節(jié)問(wèn)題需要注意。
第三天效果如下
文中如果有不對(duì)的地方歡迎指出。我是xx_cc,一只長(zhǎng)大很久但還沒(méi)有二夠的家伙。