關(guān)于 iOS 刪除緩存的那些事兒

全文約 2500 字,預(yù)計(jì)閱讀時間約 5 分鐘。

前言

事情的起因是這樣子的,前段時間閑來無聊,去翻看手機(jī)的儲存空間統(tǒng)計(jì),發(fā)現(xiàn)微信、QQ、微博等這些 app 的占用空間都很大,點(diǎn)開查看詳情,文稿與數(shù)據(jù)占了很大一部分。雖然這些 app 自帶清理緩存功能,但是清理完了之后緩存還是很大。微信和 QQ 我就不說了,有很多聊天記錄或者文件沒有刪除。但是像微博、淘寶、京東等 app ,在使用了自帶的清除緩存功能之后,其在 iOS 系統(tǒng)顯示的文稿與數(shù)據(jù)占用還是很高,讓我很不能理解。由于之前使用的 16G 儲存空間的 iPhone,被儲存空間不足折磨不停,因此希望 app 都能做好儲存空間的管理。否則很多用戶只能用腳投票了。作為一個小透明,我只是呼吁各位開發(fā)者能夠做好這個,而我在學(xué)習(xí)的過程中也會盡量注意這個情況。

鄙校論壇的官方 iOS 客戶端也提供清理緩存的功能,我就去看了看。發(fā)現(xiàn)其文稿與數(shù)據(jù)占用量極高(200 Mb+),而app自身提供的清理緩存所統(tǒng)計(jì)的數(shù)據(jù)量又極低(不到 10 Mb)。正好我自己也在做一款app練手,也正好做到緩存這一塊,因此就想探討一下文稿與數(shù)據(jù)包含了什么,應(yīng)該怎么清理緩存。

北郵人論壇 iOS 客戶端開發(fā)者:Caches里有個fsCachedData之前沒發(fā)現(xiàn)。。需要NSURLCache.sharedURLCache().removeAllResponses()搞掉。。

至于為什么不寫如何進(jìn)行緩存,一是我自己還沒怎么懂,二是網(wǎng)上已經(jīng)有很多人整理得挺好的了,我就不獻(xiàn)丑了。

沙盒(SandBox)系統(tǒng)

iOS文件系統(tǒng)將不同的app隔離,讓他們自己運(yùn)行。為了保證系統(tǒng)簡潔,iOS設(shè)備的用戶不能直接訪問文件系統(tǒng),每一個app都保存在一個沙盒中,一般來說,該app只能訪問沙盒中的數(shù)據(jù)。iOS通過沙盒系統(tǒng),保護(hù)系統(tǒng)與其他app的安全。

iOS 標(biāo)準(zhǔn)目錄:文件存在哪兒

為了安全起見,iOS app 與文件系統(tǒng)的交互被限制在app的沙盒目錄下。在安裝一個新 app 的過程中,安裝器給在沙盒中給 app 創(chuàng)建了一系列的容器。每一個容器有其特殊的職責(zé)。bundle 容器裝著 app 的 bundle,數(shù)據(jù)容器則包含著 app 和用戶的數(shù)據(jù)。數(shù)據(jù)容器分成了幾個子文件夾,app 可以使用這些文件夾來對數(shù)據(jù)進(jìn)行排序與管理。

圖1 一個iOS app的沙盒目錄
圖1 一個iOS app的沙盒目錄

如何查看 app 的沙盒目錄(模擬器 + 真機(jī))

網(wǎng)上搜到的方法很多是幾年前的方法,就算是今年發(fā)表的文章上面的圖也是直接抄的前幾年的圖片,因此沒有參考價值。本文將與時俱進(jìn),采用 Xcode 8.1 + iOS 10.1 的環(huán)境介紹如何查看app的沙盒文件。

查看 iOS 模擬器上 app 的沙盒目錄

查看在 iOS 模擬器上 app 的沙盒目錄,只需要一段代碼就可以解決問題。

是的,你沒看錯,在模擬器上面一段代碼就能解決困擾我兩天的問題。在前人的指導(dǎo)下走了很多彎路,最后發(fā)現(xiàn)了NSHomeDirectory()這個方法。

NSLog(@"%@",NSHomeDirectory());

輸出結(jié)果

/Users/username/Library/Developer/CoreSimulator/Devices/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/data/Containers/Data/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

將輸出結(jié)果打開 Finder->前往->前往文件夾,粘貼。即可查看 app 的沙盒目錄。

模擬器 app 沙盒目錄

查看 iOS 真機(jī)上 app 的沙盒目錄

查看 iOS 真機(jī)上 app 的沙盒目錄比在模擬器上稍顯復(fù)雜,但也可以輕松實(shí)現(xiàn)。

1.在 Xcode 的上部導(dǎo)航欄中選擇 Window,隨后選擇 Devices。

2.選擇相應(yīng)的 Devices 后,在 Installed Apps 里面選擇要打開查看的app,點(diǎn)擊下邊的齒輪,可以用 Download Container 將沙盒文件保存到本地。

3.在本地中將沙盒文件點(diǎn)擊右鍵,選擇顯示包內(nèi)容,即可查看沙盒文件。

真機(jī)查看沙盒結(jié)果


注意:在前面提到的環(huán)境中,上述方法只能查看 app 的 Data Container, Bundle Container 不在這一目錄下。

在沙盒目錄中,我們可以看到 Documents/、Library/、tmp/ 三個文件夾。而根據(jù) Apple 提供的文件系統(tǒng)編程指南官方文檔,我們可以對上述文件夾中應(yīng)當(dāng)存放何種文件進(jìn)行了解。以下內(nèi)容翻譯自 文件系統(tǒng)編程指南。

表1 一個 iOS app 通常使用的目錄

目錄名 描述
appName.app 這個是 app 的 bundle 。這個目錄包含了 app 和其所有的資源。
你沒有這個目錄的寫權(quán)限。為了防止篡改,bundle 目錄的簽名在 bundle 生成時生成。修改這個目錄會修改簽名并阻止 app 登錄。你只可以對所有保存在 bundle 里的資源有讀權(quán)限。更多內(nèi)容,參考資源編程指南(Resource Programming Guide)
這個目錄下的內(nèi)容不會保存在 iTunes 或者 iCloud。iTunes 會對從 app Store 購買的任何應(yīng)用執(zhí)行初始同步。
Documents/ 使用這個目錄來保存用戶生成的文件。用戶可以通過文件分享功能訪問這個目錄的內(nèi)容。因此,這個目錄你應(yīng)該只放一些你希望展示給用戶的文件。
這個目錄的文件會被 iTunes 和 iCloud 備份。
Documents/Inbox/ 使用這個目錄訪問你的app打開的外部實(shí)體。特別地,郵件客戶端會將和你的app相關(guān)的附件放在你的app的這個目錄。文件交互控制器也可能會在這個文件夾存放東西。
在這個文件夾里,你的app可以讀或者刪除文件,但是不能創(chuàng)建新文件或者修改現(xiàn)有的文件。如果用戶想要在這個文件夾里嘗試去修改文件,你的app需要悄悄地把該文件移除這個文件夾。
這個目錄的文件會被 iTunes 和 iCloud 備份。
Library/ 這是一個所有非用戶數(shù)據(jù)文件的頂級目錄。你通常把文件放到多個標(biāo)準(zhǔn)子目錄下中的一個。iOS app 通常使用 application Support 和 Cache 子文件夾,你也可以創(chuàng)建自己的子文件夾。使用 Library 子文件夾來存放任何你不想被用戶看到的文件。你的app不應(yīng)該使用這些文件夾來存放用戶數(shù)據(jù)文件。
除了 Caches 子文件夾,Library 文件夾下的內(nèi)容會被 iTunes 和 iCloud 備份。
tmp/ 使用這個文件夾來存放在臨時文件,這些臨時文件在兩次打開 app 之間不一定需要保存。當(dāng)不在需要這些文件時,你的 app 需要這個文件夾中移除它們。系統(tǒng)也可能會在你的 app 不再運(yùn)行的時候清除這個文件夾。
這個目錄的文件 不會 被 iTunes 和 iCloud 備份。

一個 iOS app 可以在 Documents、Librarytmp 文件夾下建立新的文件夾。在這個目錄下你需要更好地安排文件放置的位置。

app 的文件存放的地方

為了防止 iOS 設(shè)備同步與備份的過程持續(xù)太久,注意選擇存放文件的位置。存放了大量文件的 app 會減慢 iTunes 或者 iCloud 的備份速度。這些 app 也會消耗大量的用戶可用儲存空間,這會導(dǎo)致用戶刪除 app 或者不允許 app 的數(shù)據(jù)備份到 iCloud 中。因此,保存 app 的數(shù)據(jù)需要遵循以下幾點(diǎn)準(zhǔn)則。

  • 將用戶數(shù)據(jù)保存在 Documents/. 用戶數(shù)據(jù)包括所有你希望展示給用戶的文件——那些你希望用戶創(chuàng)建、引入、刪除或編輯的。對于一個繪畫 app,用戶數(shù)據(jù)包括任何用戶想要創(chuàng)建的圖片分揀。對于一個文本編輯器,用戶數(shù)據(jù)包括文本文件。音視頻 app 的用戶數(shù)據(jù)則可能包括用戶已經(jīng)下載的想要隨后觀看或收聽的文件。
  • 將 app 創(chuàng)建的支持文件保存在 Library/Application support/ 文件夾。通常地,在這個文件夾下包括那些 app 運(yùn)行時需要使用但應(yīng)該對用戶隱藏的文件。這個文件夾也包括從 app bundle 讀取的數(shù)據(jù)文件、配置文件、模板和修改版本資源。
  • 要記住在 Documents/ 下和 Application support/ 文件夾在默認(rèn)情況下會被備份。你可以通過調(diào)用 -[NSURL setResourceValue:forKey:error:]使用NSURLIsExcludedFromBackupKey值來防止一些文件被備份。所有可以重復(fù)創(chuàng)建或者下載的文件必須排除在備份外。特別包括那些大的多媒體文件。如果你的應(yīng)用下載音視頻文件,保證它們不在備份中。
  • 將臨時數(shù)據(jù)保存在 tmp/ 文件夾中。臨時文件包括那些在很長一段時間內(nèi)不需要持續(xù)存在的文件。記得在使用這些文件結(jié)束后刪除它們防止它們繼續(xù)占用用戶設(shè)備的空間。系統(tǒng)會在你的 app 非運(yùn)行的時候周期性地清除這些文件,因此你不能保證這些文件在你的 app 終止后還繼續(xù)存在。
  • 將數(shù)據(jù)緩存文件保存在 Library/Caches/ 文件夾中。緩存文件包括那些比臨時文件保存時間要長,但是沒有支持文件時間這么長的文件。通常來說,應(yīng)用在沒有緩存數(shù)據(jù)時可以正常運(yùn)行,但是在存在緩存文件時能夠提升性能。緩存文件包括(但不限于)數(shù)據(jù)庫緩存文件以及短暫的可下載內(nèi)容。需要注意的是,系統(tǒng)可能會刪除 Caches/ 文件夾里的內(nèi)容來釋放磁盤空間,因此你的 app 需要保證這些文件是可以重新創(chuàng)建或者下載的。

計(jì)算緩存大小與刪除緩存

重要的事情說三遍:

數(shù)據(jù)無價!

數(shù)據(jù)無價!

數(shù)據(jù)無價!

在進(jìn)行數(shù)據(jù)操作時,請牢記數(shù)據(jù)無價這一原則。防止因?yàn)檎`操作將用戶寶貴的數(shù)據(jù)刪除,造成不必要的麻煩。

計(jì)算緩存大小

- (NSUInteger)getSize {
    NSUInteger size = 0;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString * cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtPath:cachePath];
    for (NSString *fileName in fileEnumerator) {
        NSString *filePath = [cachePath stringByAppendingPathComponent:fileName];
        NSDictionary *attrs = [fileManager attributesOfItemAtPath:filePath error:nil];
        size += [attrs fileSize];
    }
    return size;
}

使用 NSCachesDirectory 得到的路徑是 Library/Caches/ 文件夾,其他文件夾如 Documents/Library/ 路徑的獲取,請參照 NSSearchPathDirectory 。

使用 enumeratorAtPath 獲取文件夾下所有文件/文件夾的路徑。類似的方法包括 subpathsAtPathsubpathsOfDirectoryAtPath 。

刪除緩存

再提醒一遍,刪除之前請?jiān)偃_認(rèn)刪除的文件不會影響程序的正常運(yùn)行。當(dāng)然了,如果保存 app 的數(shù)據(jù)沒有按照上述提到的準(zhǔn)則,則在審核時可能無法通過。

/*
  12-23 update: use removeItemAtPath to delete each subdir 
  instead of delete the root dir and then recreate it
*/
- (void)clearFile
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString * cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",cachePath);
    NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtPath:cachePath];
    for (NSString *fileName in fileEnumerator) {
        NSString *filePath = [cachePath stringByAppendingPathComponent:fileName];
        [fileManager removeItemAtPath:filePath error:nil];
    }
}

通過 enumeratorAtPath 使用 removeItemAtPath 將文件夾內(nèi)的所有子文件與文件夾刪除。注意:當(dāng)使用 removeItemAtPath 將刪除文件夾下所有內(nèi)容包含自身文件夾,與并使用 createDirectoryAtPath 重新創(chuàng)建該文件夾時,第二次調(diào)用 removeItemAtPath 不一定能將之前手動創(chuàng)建的文件夾刪除,造成緩存堆積。

遇到的一些問題

  1. 在真機(jī)調(diào)試的時候,某些數(shù)據(jù)死活刪不去,而在模擬器上沒有這個問題。考慮到可能是上一個版本遺留的文件,手動刪掉 app 再重新倒入就好了。
  2. 真機(jī)調(diào)試的時候,Library/Caches/Snapshots/ 里的內(nèi)容刪不去。至今沒有找到解決方案。
  3. 如何定時清理緩存也是一個研究點(diǎn)。

寫在最后

本篇文章通過介紹沙盒系統(tǒng),查看沙盒文件,通過代碼計(jì)算緩存大小與刪除緩存四個部分對 iOS app 對文稿與數(shù)據(jù)部分進(jìn)行理解和分析。想要深入了解,可以閱讀 Apple 提供的文件系統(tǒng)編程指南官方文檔,和 SDWebImage 的 SDImageCache 部分源碼。

參考文獻(xiàn)

[1] Apple 文件系統(tǒng)編程指南官方文檔

[2] Apple API Reference NSFileManager 部分

[3] iOS查看沙盒文件圖文教程(真機(jī)+模擬器)-Darren.Von

[4] SDWebImage 源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,026評論 4 61
  • ? 婷菇?jīng)? 極簡白色不對稱流蘇耳環(huán) 長款 復(fù)古軟妹耳飾 女 淑女耳墜
    婷菇?jīng)鍪肿?/span>閱讀 344評論 0 0
  • 不經(jīng)意間 一個身影 攪動了我的心 思緒 像漣漪 又像波浪 在涌動 在翻滾 是石子 無數(shù)的石子 投進(jìn)了那泊寧靜的水 ...
    大石頭Stone閱讀 523評論 12 14
  • 今天,我們吃完晚飯,就要跟爺爺奶奶告別了,因?yàn)槲液蛬寢?、爸爸,要坐火車到貴州的鎮(zhèn)遠(yuǎn)。這時我正好剛剛玩完游戲...
    小胡_804d閱讀 192評論 0 0
  • 你給我的全世界,在我這里只有傷害 當(dāng)你的巴掌落在我瘦小的軀體上時,我已經(jīng)感覺不到你口里說的愛,護(hù)...... 當(dāng)你...
    沙漏_2464閱讀 572評論 0 1

友情鏈接更多精彩內(nèi)容