應(yīng)用中清除緩存的相關(guān)處理

  • 設(shè)置界面?中清除緩存的處理---** 每個App幾乎都有清除緩存的功能**

  • 手機上的磁盤緩存 == 從網(wǎng)絡(luò)上下載的數(shù)據(jù) + 寫入的數(shù)據(jù)
  • 手機上的磁盤緩存的數(shù)據(jù)類型 == 圖片 + 多媒體文件(音頻視頻等)
  • 它們存在于沙盒之中
  • 這里要清除緩存,就要拿到沙盒中存在的緩存的大小黎泣,就是看我們下載的圖片文件有多大恕刘,然后把它顯示在cell當(dāng)中
  • 因為我們下載圖片用到是SDWebImage框架,所以我們要獲取所下載圖片的緩存大小抒倚,最簡單的方法也是使用SDWebImage里面的東西--SDImageCache

  • 獲取磁盤緩存的大小褐着,它是一個單例
  • 在我們Mac 和 iOS 中數(shù)據(jù)的大小不是以1024為單位的而是以1000為單位,不用弄?混淆了
    // 這里打印出來的單位是Mb
    CYLog(@"%f", [SDImageCache sharedImageCache].getSize / 1000.0 / 1000.0);
    // 拿到沙盒的路徑
    CYLog(@"%@", NSTemporaryDirectory());

  • 沙盒的結(jié)構(gòu)
    • Ducuments中不允許放太大的文件托呕,那里面的文件是要備份到iTunes中去的含蓉,也就是說要備份到蘋果的云服務(wù)器中去。如果你把下載的緩存文件放在其中项郊,蘋果是不允許你的應(yīng)用通過的
    • Library文件夾里面存放在緩存文件(整個緩存是在default文件夾中)
    • temp文件夾存放臨時文件

  • 怎么去獲取一個文件夾或者文件夾的大小呢馅扣?
    • SDWebImage用了一個類:FileManager
    • 但它只能獲取文件的大小,無法獲取整個文件夾的大小
    // 文件管理者
    NSFileManager *mgr = [NSFileManager defaultManager];
  • 怎么去找到default文件夾呆抑,拿到它的路徑呢岂嗓?
    // 先拿到caches文件夾路徑(它返回的是數(shù)組,所以取第一個)
    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    NSString *file = [caches stringByAppendingPathComponent:@"default"];// 拼接的路徑
//    NSString *file = [caches stringByAppendingString:@"default"];// 這是拼接的字符串
  • 獲取文件夾的屬性
// 獲得文件屬性
// 它?只給你文件夾這個殼子有多大鹊碍,沒有給里面的文件有多大
NSDictionary *attrs = [mgr attributesOfItemAtPath:file error:nil];
  • 在Mac中不能直接拿到文件夾的大小厌殉,只能對文件夾進行一層一層的遍歷食绿,去拿到里面文件的大小,然后全部加起來
  • 所以我們得遍歷文件夾里面所以的文件公罕,然后把里面所有文件的FileSize加起來
  • 第一種方式
    // 總大小
    NSInteger size = 0;

    // 文件路徑
    // 先拿到caches文件夾路徑(它返回的是數(shù)組器紧,所以取第一個)
    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    NSString *file = [caches stringByAppendingPathComponent:@"default"];// 拼接的路徑
//    NSString *file = [caches stringByAppendingString:@"default"];// 這是拼接的字符串

    // 文件管理者
    NSFileManager *mgr = [NSFileManager defaultManager];

    // 獲得文件夾中的所有內(nèi)容
//        NSArray *contents = [mgr contentsOfDirectoryAtPath:file error:nil];
//        它只能獲得它當(dāng)前文件夾的內(nèi)容,不能往里面深挖楼眷,這里不用它
//        subpaths 獲取文件夾里面文件的子路徑铲汪,什么文件都能拿到了(文件夾能拿到,文件夾里面的文件也能拿到)
//        所以用subpaths就是做好的罐柳,只有給我們一個最根的文件夾掌腰,我們就能找到里面所有的文件,不需要一遍一遍遞歸去找了
    NSArray *subpaths = [mgr subpathsAtPath:file];
    for (NSString *subpath in subpaths) {
        // 獲得全路徑
        NSString *fullSubpath = [file stringByAppendingPathComponent:subpath];
        // 獲得文件屬性
        NSDictionary *attrs = [mgr attributesOfItemAtPath:fullSubpath error:nil];
//        size += [attrs[NSFileSize] integerValue];
        size += attrs.fileSize;
    }
  • 這個方式是通過拼接所有的路徑而去獲取緩存的大小

  • 但是我還有另外一種方式

  • 第二種方式

    // 總大小
    NSInteger size = 0;

    // 文件路徑
    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    NSString *file = [caches stringByAppendingPathComponent:@"default"];

    // 文件管理者
    NSFileManager *mgr = [NSFileManager defaultManager];

    // 獲得文件夾中的所有內(nèi)容
    // enumerator遍歷器张吉,可以通過for..in..遍歷所有的子路徑
    NSDirectoryEnumerator *enumerator = [mgr enumeratorAtPath:file];
    for (NSString *subpath in enumerator) {
        // 獲得全路徑
        NSString *fullSubpath = [file stringByAppendingPathComponent:subpath];
        // 獲得文件屬性
        NSDictionary *attrs = [mgr attributesOfItemAtPath:fullSubpath error:nil];
//        size += [attrs[NSFileSize] integerValue];
//       通過key直接取出來
        size += attrs.fileSize;
    }
  • 第二種方式的原理:怎么獲取一個文件夾內(nèi)容的大小齿梁,把一個文件夾給我,有了文件夾路徑肮蛹,有了manager勺择,然后獲得一個可以獲取文件夾路徑的遍歷器,它通過for...in...可以遍歷出所有文件夾的子路徑伦忠。通過子路徑生成一個完整的路徑(全路徑)省核,我就獲取所有子路徑文件的大小。把它所有的文件夾大小加起來昆码,就是我們總文件的大小气忠。
  • 下面是SDWebImage的實現(xiàn)方法:
- (NSUInteger)getSize {
    __block NSUInteger size = 0;
    dispatch_sync(self.ioQueue, ^{
        NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath];
        for (NSString *fileName in fileEnumerator) {
            NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];
            NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
            size += [attrs fileSize];
        }
    });
    return size;
}

  • SDWebImage底層在這里是怎么實現(xiàn):把一個文件夾傳進去,獲取所有的迭代器未桥,從迭代器中獲取所有的子路徑通過文件夾路徑拼接一個文件名變成一個全路徑笔刹,然后再通過attributes這個屬性累加起來;但是冬耿,它是直接調(diào)用字典這種方法(我們是前面是通過key取出來的),而且是放在一個自己創(chuàng)建的一個串行隊列中去的萌壳,也就是異步的
  • 但是現(xiàn)在放在viewDidLoad中算亦镶,肯定是有問題的,比較耗時袱瓮,我們得修改

  • 我們先抽取一個分類(今后你給一個字符串給我缤骨,就能獲取字符串對應(yīng)路徑的大小)
    • 但是嚴謹起見尺借,分類中要考慮的問題:
      • 可能是個文件夾绊起,也可能是個文件,所以先得判斷這個文件存不存在燎斩,還要判斷這個路徑下是文件還是文件夾
      • 路徑可能也會錯虱歪,也得判斷
  • NSString+CYExtension.h文件中
#import <Foundation/Foundation.h>

@interface NSString (CYExtension)
- (NSInteger)fileSize;
@end
  • NSString+CYExtension.m文件中
#import "NSString+CYExtension.h"

@implementation NSString (CYExtension)
// 判斷一個路徑是文件夾 or 文件
//    [[mgr attributesOfItemAtPath:self error:nil].fileType isEqualToString:NSFileTypeDirectory];

- (NSInteger)fileSize
{
    // 文件管理者
    NSFileManager *mgr = [NSFileManager defaultManager];
    // 是否為文件夾
    BOOL isDirectory = NO;
    // 這個路徑是否存在
    BOOL exists = [mgr fileExistsAtPath:self isDirectory:&isDirectory];
    // 路徑不存在
    if (exists == NO) return 0;

    if (isDirectory) { // 文件夾
        // 總大小
        NSInteger size = 0;
        // 獲得文件夾中的所有內(nèi)容
        NSDirectoryEnumerator *enumerator = [mgr enumeratorAtPath:self];
        for (NSString *subpath in enumerator) {
            // 獲得全路徑
            NSString *fullSubpath = [self stringByAppendingPathComponent:subpath];
            // 獲得文件屬性
            size += [mgr attributesOfItemAtPath:fullSubpath error:nil].fileSize;
        }
        return size;
    } else { // 文件
        return [mgr attributesOfItemAtPath:self error:nil].fileSize;
    }
}
@end
  • 然后放入PCH文件中
  • 所以今后想算一個文件夾或者文件的大小,你直接將這個分類拽走就行了,給我傳一個路徑就ok了

  • 在計算文件夾大小時骗露,我們有過體驗互拾,文件夾大的話,要計算很長一段時間萧落,所以清除緩存和計算緩存大小都要放在子線程中
  • 接下來我們就要將App中緩存的大小算出來践美,顯示在cell中
    • 如果我直接調(diào)用cacheFile.fileSize/1000.0/1000.0在cell中計算并顯示,如果文件多了找岖,緩存多了陨倡,文件夾層級結(jié)構(gòu)多了,遍歷起來就會很耗時许布,所以這個時候調(diào)用fileSize兴革,里面的for循環(huán)就會遍歷很久,就會卡頓了爹脾。
    • 這時候帖旨,你可能就會想到放在子線程,開啟一個全局隊列灵妨,把計算緩存的代碼放在其中解阅。但是其實放在這里是不太好的。因為子線程是不允許刷新UI界面的泌霍。如果你硬是要這么干呢货抄,也可以,在子線程中把緩存大小算出來朱转,然后又再開啟一個主線程蟹地,顯示緩存大小的文字(你會發(fā)現(xiàn),是不會卡頓了藤为,但是剛剛進入界面的時候怪与,cell中是空白的,你拖拽之后才會顯示出來)所以這樣也是不推薦的
        // 計算大小
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            // 計算緩存大小
            NSString *cacheFile = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"default"];
            NSString *text = [NSString stringWithFormat:@"清除緩存(%1.fMB)",cacheFile.fileSize / 1000.0 / 1000.0] / 1000.0];

            // 回到主線程
            dispatch_sync(dispatch_get_main_queue(), ^{
                self.textLabel.text = text;
            });
        });
  • 對于這樣一種特殊要求的cell缅疟,我們就自定義了--CYClearCacheCell
  • 將緩存路徑寫成一個宏分别,因為可能總是會用到
/** 緩存路徑 */
#define CYCacheFile [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"default"]
  • 重寫它的initWithStyle:方法
  • 你如果不想用GCD,那就用NSOperationQueue存淫,先在子線程中計算耘斩,然后在主線程中刷新,這樣更加面向?qū)ο?/li>
  • 一般當(dāng)你計算緩存的時候桅咆,你最好弄一個圈圈在哪里轉(zhuǎn)括授,這個時候用戶不能點擊;算完之后,圈圈消失荚虚,箭頭出現(xiàn)薛夜,這個時候用戶?才可以點擊
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.textLabel.text = @"清除緩存";

        // 禁止點擊事件
        self.userInteractionEnabled = NO;

        // 右邊顯示圈圈
        UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        [loadingView startAnimating];
        self.accessoryView = loadingView;

        // 計算大小
        [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
            // 計算緩存大小
            NSInteger size = CYCacheFile.fileSize;
            NSString *text = [NSString stringWithFormat:@"清除緩存(%1.fMB)",size / 1000.0 / 1000.0] / 1000.0];

            // 回到主線程
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                self.textLabel.text = text;
                self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
                self.accessoryView = nil;// accessoryView的優(yōu)先級是高于UITableViewCellAccessoryDisclosureIndicator(沒有指針指針就掛了)
                // 允許點擊事件
                self.userInteractionEnabled = YES;
            }];
        }];
    }
    return self;
}
  • 還有就是你清除緩存的地方,不一定是KB,MB.也可能是GB.所以得分情況判斷
// 計算大小
        [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
            // 計算緩存大小
            NSInteger size = CYCacheFile.fileSize;
            CGFloat unit = 1000.0;
            NSString *sizeText = nil;
            if (size >= unit * unit * unit) { // >= 1GB
                sizeText = [NSString stringWithFormat:@"%.1fGB", size / unit / unit / unit];
            } else if (size >= unit * unit) { // >= 1MB
                sizeText = [NSString stringWithFormat:@"%.1fMB", size / unit / unit];
            } else if (size >= unit) { // >= 1KB
                sizeText = [NSString stringWithFormat:@"%.1fKB", size / unit];
            } else { // >= 0B
                sizeText = [NSString stringWithFormat:@"%zdB", size];
            }
            NSString *text = [NSString stringWithFormat:@"%@(%@)", CYDefaultText, sizeText];
  • 每個cell被點擊選中的時候曲管,默認都有一個顏色却邓,通過實現(xiàn)代理方法,監(jiān)聽cell的點擊院水,讓系統(tǒng)默認的灰色在點擊的時候不顯現(xiàn)腊徙,這個有用
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 取消選中(你一點擊,我就取消選中檬某,那樣的話撬腾,cell默認的灰色就不見了)
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

  • 那現(xiàn)在真的要清除緩存了
    • 怎么清除呢?把文件夾刪掉
  • 刪除整一個文件夾恢恼,如果東西多民傻,它肯定刪除得慢,耗時操作放在在子線程中進行
  • 而且好多應(yīng)用在清除緩存的時候都會彈出一個框提示场斑,而且你還得將你的文字改過來(清除完了就沒有大小了 )
    • 有一個小細節(jié)漓踢,假設(shè)我們緩存算得比較慢的時候,可能還沒算完漏隐,用戶就去點擊了喧半,這樣的話就不合理了。一般是要算完之后青责,才允許用戶去點擊挺据。
    • 所以一進來的時候,就要禁止用戶點擊事件脖隶”饽停回到主線程算完后,允許用戶點擊产阱,而且在你清除掉之后婉称,也應(yīng)該禁止它點擊(取決產(chǎn)品要求)這才是合理的
- (void)clearCache
{
    [SVProgressHUD showWithStatus:@"正在清除緩存" maskType:SVProgressHUDMaskTypeBlack];

    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        [[NSFileManager defaultManager] removeItemAtPath:CYCacheFile error:nil];

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [SVProgressHUD showSuccessWithStatus:@"清除成功"];

            self.textLabel.text = CYDefaultText;

            // 禁止點擊事件
            self.userInteractionEnabled = NO;
        }];
    }];
}
 // 清除緩存(這個方法是:你直接傳一個行號給我,我返回這一行對應(yīng)的cell給你构蹬,然后調(diào)用clearCache:方法就行了)
    CYClearCacheCell *cell = (CYClearCacheCell *)[tableView cellForRowAtIndexPath:indexPath];
    [cell clearCache];

  • 清除緩存的邏輯:
    • 首先酿矢,在我們的控制器中注冊一下cell,告訴它這種標識對應(yīng)這種類型的cell怎燥。在返回cell的時候就通過這種標識返回這個cell去。cell一旦返回就顯示到界面里來了蜜暑。
    • cell里面的功能呢铐姚?一旦初始化這個cell,我們首先設(shè)置文字為“清除緩存”。然后在它的右邊顯示一個圈圈讓它轉(zhuǎn)隐绵。在它轉(zhuǎn)的過程中之众,我們在子線程中計算它緩存的大小。算完之后依许,我們就回到主線程棺禾,把緩存大小顯示出來,并且把這個圈圈銷毀掉峭跳,在最右邊顯示一個箭頭膘婶。點擊這個cell的時候,來到控制器蛀醉,調(diào)用這個cell的clearCache:方法悬襟。一旦調(diào)用clearCache:方法。我們首先彈出一個框拯刁,告訴它:"正在清除緩存"脊岳,在子線程把文件夾給刪掉(因為它可能很多,刪除會刪得很耗時)垛玻,刪掉后割捅,我們回到主線程,告訴它我們“清除成功”帚桩,并且把文字恢復(fù)成清除緩存

  • ?cell循環(huán)利用的問題
  • 你在設(shè)置界面亿驾,可不是只有一個“清除緩存”這樣的cell,在應(yīng)用中是還有許多其它cell的(這里我們假如將控制器設(shè)置為5組朗儒,每組5行颊乘。你會發(fā)現(xiàn):其余的cell也變成和清除緩存一樣的cell)這樣的話就牽扯到一個問題:循環(huán)運用的問題:
  • TableView中有許多的cell,你向上或者向下拖拽的時候醉锄,“清除緩存”的cell乏悄,被扔進了緩存池中,你再往上或者往下拖的時候恳不,你就得取別的cell檩小,但是緩存池中剛剛好有一個“清除緩存”的cell,(按照以前的開發(fā)模式烟勋,你就得把“清除緩存”的cell改成別的cell规求。如果你有拖拽一下,你又得把別的cell拿過來改成清除緩存的cell) 會有這樣的麻煩問題卵惦。所以為了解決這樣的麻煩問題阻肿,我們干脆這么做:只要“清除緩存”的cell和其他cell的標識不一樣就行了,這樣后面的cell循環(huán)利用的時候沮尿,就不會去拿我“清除緩存”的cell了(假設(shè)清除緩存cell的標識為A丛塌,其他cell為D较解。當(dāng)我的清除緩存的cell被扔到了在緩存池中,而滑動操作又需要其它D類型的cell的時候赴邻,我們就去緩存池中去找印衔,緩存池中沒有D標識的,我們就新創(chuàng)建一個姥敛。反正后面需要D標識的就找D標識的cell奸焙,需要“清除緩存”的cell,就找A標識的cell彤敛。這樣的話与帆,我們A標識的cell永遠都不會用錯到其它地方去)
  • 今后遇到像這種“清除緩存”的cell,也就是所有cell中它最特殊的cell臊泌,其它cell和它完全不一樣鲤桥,也就是說其它cell不可能和它循環(huán)利用的這樣的特殊的cell。一旦循環(huán)利用會很麻煩的渠概,你干脆把它獨立出來茶凳,搞一個全新的cell,給它注冊一個全新的標識播揪。
  • 所以我們得判斷贮喧,而且在判斷之前,我們得先做一件事猪狈,注冊兩種類型的cell箱沦。到時候我們只認標識就可以了
static NSString * const CYClearCacheCellId = @"clearCache";
static NSString * const CYOtherCellId = @"other";
static NSString * const CYThirdCellId = @"third";
  • 注冊完后,也要判斷
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0 && indexPath.row == 0) { // 清除緩存的cell
        CYClearCacheCell *cell = [tableView dequeueReusableCellWithIdentifier:CYClearCacheCellId];
        [cell updateStatus];
        return cell;
    } else if (indexPath.section == 1 && indexPath.row == 2) {
        return [tableView dequeueReusableCellWithIdentifier:CYThirdCellId];
    } else {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CYOtherCellId];
        cell.textLabel.text = [NSString stringWithFormat:@"%zd - %zd", indexPath.section, indexPath.row];
        return cell;
    }
}
  • 所以這個時候雇庙,我們就可以放心大膽的把內(nèi)容封裝在CYClearCacheCell中了谓形。因為它里面封裝的內(nèi)容只會顯示在CYClearCacheCell上,不會影響到其他人疆前。如果你的cell是要循環(huán)利用的寒跳,你封裝到CYClearCacheCell中是不合適的,但是現(xiàn)在就可以放心大膽了竹椒。這個cell是獨立的童太,沒有人和他搶,所以內(nèi)容顯示到它身上就可以了胸完,直接拿到它操作就可以了书释,所以這個cell是不會循環(huán)利用的。
    • 只不過還有一個小問題小細節(jié)的處理:在iOS中赊窥。默認有個特點:當(dāng)你的程序進入后臺爆惧,或者說你這個View暫時不在界面。就像當(dāng)這個“清除緩存”的cell锨能,離開屏幕检激,進入緩存池肴捉,它會將一些不必要的操作停掉,比如說動畫叔收。它就會將它里面的所有動畫停掉,包括像imageView的一些動畫傲隶,或者這個UIActivityIndicatorView的一些動畫(轉(zhuǎn)圈圈)它都會停掉饺律,特別是你的涂層動畫,核心動畫它都會停掉跺株。所以我們要進行狀態(tài)的判斷复濒,來刷新界面)
    • ?場景:用戶點擊清除緩存,又向下拖拽很快乒省,本來還在轉(zhuǎn)圈圈計算緩存大小巧颈,轉(zhuǎn)圈圈動畫停止了。這只是個小細節(jié)袖扛。也就是我我們要判斷圈圈的狀態(tài):在拖拽時砸泛,cellForRowAtIndexPath:方法會調(diào)用,我們在這里進行一個圈圈狀態(tài)的判斷蛆封。如果算完了唇礁,我們就不需要圈圈。沒算完惨篱,繼續(xù)算盏筐,繼續(xù)轉(zhuǎn)圈圈,不能讓他一往下拖砸讳,圈圈就消失了琢融。
- (void)updateStatus
{
    if (self.accessoryView == nil) return;

    // 讓圈圈繼續(xù)旋轉(zhuǎn)
    UIActivityIndicatorView *loadingView = (UIActivityIndicatorView *)self.accessoryView;
    [loadingView startAnimating];
}
  • 每一個用什么類型的cell,你通過標識就可以了簿寂,它會自動創(chuàng)建對應(yīng)類型的cell漾抬,或者去緩存池中找。所以以后凡是你的tableview里面發(fā)現(xiàn)有好幾種不一樣的cell陶耍,而且感覺那個cell和其它cell根本沒法循環(huán)利用奋蔚,但是其它的大部分cell又可以循環(huán)利用,那就讓大部分的cell用同樣類型的標識就可以了烈钞,特殊的給定特殊的標識

  • 最后在CYSettingViewController.m文件中
#import "CYSettingViewController.h"
#import <SDImageCache.h>
#import "CYClearCacheCell.h"
#import "CYThirdCell.h"

@interface CYSettingViewController ()

@end

@implementation CYSettingViewController

static NSString * const CYClearCacheCellId = @"clearCache";
static NSString * const CYOtherCellId = @"other";
static NSString * const CYThirdCellId = @"third";

- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.title = @"設(shè)置";
    self.view.backgroundColor = CYCommonBgColor;

    [self.tableView registerClass:[CYClearCacheCell class] forCellReuseIdentifier:CYClearCacheCellId];
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CYOtherCellId];
    [self.tableView registerClass:[CYThirdCell class] forCellReuseIdentifier:CYThirdCellId];

    // 設(shè)置內(nèi)邊距(-25代表:所有內(nèi)容往上移動25)
    self.tableView.contentInset = UIEdgeInsetsMake(CYCommonMargin - 35, 0, 0, 0);
}

#pragma mark - <數(shù)據(jù)源>
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 5;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0 && indexPath.row == 0) { // 清除緩存的cell
        CYClearCacheCell *cell = [tableView dequeueReusableCellWithIdentifier:CYClearCacheCellId];
        [cell updateStatus];
        return cell;
    } else if (indexPath.section == 1 && indexPath.row == 2) {
        return [tableView dequeueReusableCellWithIdentifier:CYThirdCellId];
    } else {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CYOtherCellId];
        cell.textLabel.text = [NSString stringWithFormat:@"%zd - %zd", indexPath.section, indexPath.row];
        return cell;
    }
}

#pragma mark - <代理>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 取消選中
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    // 清除緩存
    CYClearCacheCell *cell = (CYClearCacheCell *)[tableView cellForRowAtIndexPath:indexPath];
    [cell clearCache];
}
@end
  • 在CYClearCacheCell.h文件中
#import <UIKit/UIKit.h>

@interface CYClearCacheCell : UITableViewCell

- (void)clearCache;
/**
 * 更新狀態(tài)
 */
- (void)updateStatus;
@end
  • 在CYClearCacheCell.m文件中
#import "CYClearCacheCell.h"
#import <SVProgressHUD.h>

/** 緩存路徑 */
#define CYCacheFile [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"default"]

static NSString * const CYDefaultText = @"清除緩存";

@implementation CYClearCacheCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.textLabel.text = CYDefaultText;

        // 禁止點擊事件
        self.userInteractionEnabled = NO;

        // 右邊顯示圈圈
        UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        [loadingView startAnimating];
        self.accessoryView = loadingView;

        // 計算大小
        [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
            // 計算緩存大小
            NSInteger size = CYCacheFile.fileSize;
            CGFloat unit = 1000.0;
            NSString *sizeText = nil;
            if (size >= unit * unit * unit) { // >= 1GB
                sizeText = [NSString stringWithFormat:@"%.1fGB", size / unit / unit / unit];
            } else if (size >= unit * unit) { // >= 1MB
                sizeText = [NSString stringWithFormat:@"%.1fMB", size / unit / unit];
            } else if (size >= unit) { // >= 1KB
                sizeText = [NSString stringWithFormat:@"%.1fKB", size / unit];
            } else { // >= 0B
                sizeText = [NSString stringWithFormat:@"%zdB", size];
            }
            NSString *text = [NSString stringWithFormat:@"%@(%@)", CYDefaultText, sizeText];

            // 回到主線程
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                self.textLabel.text = text;
                self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
                self.accessoryView = nil;// accessoryView的優(yōu)先級是高于UITableViewCellAccessoryDisclosureIndicator(沒有指針指針就掛了)
                // 允許點擊事件
                self.userInteractionEnabled = YES;
            }];
        }];
    }
    return self;
}

- (void)updateStatus
{
    if (self.accessoryView == nil) return;

    // 讓圈圈繼續(xù)旋轉(zhuǎn)
    UIActivityIndicatorView *loadingView = (UIActivityIndicatorView *)self.accessoryView;
    [loadingView startAnimating];
}

- (void)clearCache
{
    [SVProgressHUD showWithStatus:@"正在清除緩存" maskType:SVProgressHUDMaskTypeBlack];

    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        [[NSFileManager defaultManager] removeItemAtPath:CYCacheFile error:nil];

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [SVProgressHUD showSuccessWithStatus:@"清除成功"];

            self.textLabel.text = CYDefaultText;

            // 禁止點擊事件
            self.userInteractionEnabled = NO;
        }];
    }];
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市毯欣,隨后出現(xiàn)的幾起案子馒过,更是在濱河造成了極大的恐慌,老刑警劉巖酗钞,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腹忽,死亡現(xiàn)場離奇詭異来累,居然都是意外死亡,警方通過查閱死者的電腦和手機窘奏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門嘹锁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人着裹,你說我怎么就攤上這事领猾。” “怎么了骇扇?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵摔竿,是天一觀的道長。 經(jīng)常有香客問我少孝,道長继低,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任稍走,我火速辦了婚禮袁翁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钱磅。我一直安慰自己梦裂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布盖淡。 她就那樣靜靜地躺著年柠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪褪迟。 梳的紋絲不亂的頭發(fā)上冗恨,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音味赃,去河邊找鬼掀抹。 笑死,一個胖子當(dāng)著我的面吹牛心俗,可吹牛的內(nèi)容都是我干的傲武。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼城榛,長吁一口氣:“原來是場噩夢啊……” “哼揪利!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起狠持,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤疟位,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后喘垂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甜刻,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡绍撞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了得院。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傻铣。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尿招,靈堂內(nèi)的尸體忽然破棺而出矾柜,到底是詐尸還是另有隱情,我是刑警寧澤就谜,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站里覆,受9級特大地震影響丧荐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喧枷,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一虹统、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隧甚,春花似錦车荔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帽借,卻和暖如春珠增,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砍艾。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工蒂教, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脆荷。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓凝垛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蜓谋。 傳聞我的和親對象是個殘疾皇子梦皮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)孤澎,斷路器届氢,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評論 25 707
  • 界下科技:醫(yī)保移動支付讓患者更省心 4月11日,鄭州市人社局發(fā)布信息覆旭,為進一步方便參保購藥就醫(yī)退子,鄭州市社保局數(shù)據(jù)中...
    界下科技閱讀 229評論 0 0
  • 今天加班岖妄,早早到單位,開始站樁寂祥。 今天腰部隨著時間增加荐虐,出現(xiàn)一次一次輕微的松動,就像一點一點落入套扣的感覺丸凭,咔的一...
    塔羅師默默閱讀 220評論 0 0