關于 iOS 刪除緩存的那些事兒

全文約 2500 字,預計閱讀時間約 5 分鐘。

前言

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

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

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

至于為什么不寫如何進行緩存,一是我自己還沒怎么懂,二是網上已經有很多人整理得挺好的了,我就不獻丑了。

沙盒(SandBox)系統

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

iOS 標準目錄:文件存在哪兒

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

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

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

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

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

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

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

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

輸出結果

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

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

模擬器 app 沙盒目錄

查看 iOS 真機上 app 的沙盒目錄

查看 iOS 真機上 app 的沙盒目錄比在模擬器上稍顯復雜,但也可以輕松實現。

1.在 Xcode 的上部導航欄中選擇 Window,隨后選擇 Devices。

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

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

真機查看沙盒結果


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

在沙盒目錄中,我們可以看到 Documents/Library/tmp/ 三個文件夾。而根據 Apple 提供的文件系統編程指南官方文檔,我們可以對上述文件夾中應當存放何種文件進行了解。以下內容翻譯自 文件系統編程指南

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

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

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

app 的文件存放的地方

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

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

計算緩存大小與刪除緩存

重要的事情說三遍:

數據無價!

數據無價!

數據無價!

在進行數據操作時,請牢記數據無價這一原則。防止因為誤操作將用戶寶貴的數據刪除,造成不必要的麻煩。

計算緩存大小

- (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

刪除緩存

再提醒一遍,刪除之前請再三確認刪除的文件不會影響程序的正常運行。當然了,如果保存 app 的數據沒有按照上述提到的準則,則在審核時可能無法通過。

/*
  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 將文件夾內的所有子文件與文件夾刪除。注意:當使用 removeItemAtPath 將刪除文件夾下所有內容包含自身文件夾,與并使用 createDirectoryAtPath 重新創建該文件夾時,第二次調用 removeItemAtPath 不一定能將之前手動創建的文件夾刪除,造成緩存堆積。

遇到的一些問題

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

寫在最后

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

參考文獻

[1] Apple 文件系統編程指南官方文檔

[2] Apple API Reference NSFileManager 部分

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

[4] SDWebImage 源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,176評論 4 61
  • ? 婷菇涼? 極簡白色不對稱流蘇耳環 長款 復古軟妹耳飾 女 淑女耳墜
    婷菇涼手作閱讀 306評論 0 0
  • 不經意間 一個身影 攪動了我的心 思緒 像漣漪 又像波浪 在涌動 在翻滾 是石子 無數的石子 投進了那泊寧靜的水 ...
    大石頭Stone閱讀 506評論 12 14
  • 今天,我們吃完晚飯,就要跟爺爺奶奶告別了,因為我和媽媽、爸爸,要坐火車到貴州的鎮遠。這時我正好剛剛玩完游戲...
    小胡_804d閱讀 166評論 0 0
  • 你給我的全世界,在我這里只有傷害 當你的巴掌落在我瘦小的軀體上時,我已經感覺不到你口里說的愛,護...... 當你...
    沙漏_2464閱讀 513評論 0 1