百度APP iOS端磁盘优化实践(上)
01 概览
在APP的开发中,磁盘管理已成为不可忽视的部分。随着功能的复杂化和数据量的快速增长,如何高效管理磁盘空间直接关系到用户体验和APP性能。本文将结合磁盘管理的实践经验,详细介绍iOS沙盒环境下的文件存储规范,探讨业务缓存、用户资产及系统缓存的清理策略。同时,分享自动清理与手动清理相结合的机制,展示如何在不同触发条件下合理执行磁盘清理。文章使用文心一言辅助编写。
02 磁盘系统介绍
2.1 ios沙盒系统
沙盒机制是iOS系统中的一种安全体系。每个iOS程序都有一个独立的文件系统,而且只能在对应的文件系统中进行操作,此区域被称之为沙盒(SandBox)。APP中所有文件都保存在此,如文本文件、图片、图标、媒体资源、Mach-O等。主要包含4个目录 MyApp.app、Documents、Library、tmp。
MyApp.app目录包含应用程序及其所有资源,即.ipa安装包解压后的.app内容,仅支持只读访问。Documents目录用于存储用户生成的内容,可以通过文件共享提供给用户,并由iCloud备份。Library目录则用于存放非用户数据文件的顶级目录,通常包含几个标准子目录,如Application Support和Caches,并由iCloud(Caches除外)备份。而tmp目录用于写入临时文件,这些文件不需要在应用程序启动之间保留,当不再需要时应由应用程序删除,且不被iCloud备份。 
2.2 获取目录API
NSSearchPathForDirectoriesInDomains()函数用于查找目录,返回指定范围内的指定名称的目录的路径集合。
// 获取沙盒主目录路径
NSString *homeDir = NSHomeDirectory();
// 获取Documents目录路径
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
// 获取Library的目录路径
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
// 获取Caches目录路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
// 获取tmp目录路径
NSString *tmpDir = NSTemporaryDirectory();
//应用程序程序包的路径
[[NSBundle mainBundle] bundlePath];
2.3 文件存储规范
iOS项目开发中,文件管理至关重要。我们结合Apple官方指导与项目实践,形成了一套详细的文件使用规范。这些规范不仅遵循了iCloud备份策略,还充分考虑了文件类型特性和业务需求。结合业务使用场景,能够更准确地判断哪些文件是临时数据、哪些是用户生成的重要文件,为后续进行磁盘监控和清理提供了便利。
MyApp.app:
-
用途:应用程序的包,此目录包含应用程序Mach-O可执行文件及其所有资源,iCloud默认不备份此目录。
-
使用规范:
-
开发者不能写入此目录。写入此目录会影响签名导致APP无法启动。
-
开发者可以获得对应用程序包中存储的任何资源的只读访问权限。
Documents:
-
用途:存储用户生成的内容的顶级目录,iCloud默认备份此目录。
-
使用规范:
-
该目录应仅包含开发者可能希望向用户公开的文件。
Documents/Inbox:
-
用途:存储通过外部共享方式导入到APP的文件,iCloud默认备份此目录。
-
使用规范:
-
开发者不应自行在此目录下创建文件。
-
开发者可读可删,将此目录中文件移出后再编辑。
Library:
-
用途:存储非用户数据文件的顶级目录,iCloud默认备份此目录(Caches除外)。
-
使用规范:
-
可以创建自定义子目录,用于保存不向用户公开的任何文件。
-
各业务方需要创建业务相关的子目录存储数据。
Library/Caches:
-
用途:用于存放再次下载或重新生成的数据,iCloud不会备份此目录。
-
使用规范:
-
存放可以重新下载或生成的数据,如图片缓存文件、临时文件等。
-
系统在系统储存不足时可能会删除该目录以释放磁盘空间。
-
各业务数据缓存文件应放在/Library/Caches的子目录下,方便管理。
Library/Application Support:
-
用途:用于存储APP配置和数据文件,iCloud默认备份此目录。
-
使用规范:
-
存放程序配置和数据文件,如配置文件、模板等,不应存放缓存文件。
-
避免在此目录下创建不必要的文件,以减少备份时间和存储空间占用。
Library/Preferences:
-
用途:用于存储应用程序的首选项值,iCloud默认备份此目录。
-
存放建议:
-
开发者不应自行在此目录下创建文件。
-
NSUserDefaults或CFPreferences来获取和设置APP的首选项值。
tmp:
-
用途:用于存放临时数据,iCloud不会备份此目录。
-
存放建议:
-
仅存放临时数据,开发者应在使用完这些文件后及时删除。
-
系统会清除目录下文件,应用程序终止后可能不存在。
-
不推荐业务方使用此目录存放重要数据。
2.3.1 文件命名规则
-
文件夹命名推荐Pascal命名法,第一个字母大写。
-
一个业务最多3个二级路径:
-
业务数据放在Library/下的一个目录下。
-
数据缓存文件放在Library/Caches的一个目录下。
-
用户数据放Documents/下的一个目录下。
2.3.2 iCloud备份与恢复
iCloud会默认同步Documents、Library 目录下的文件(Caches子目录除外),用户在设置中开启iCloud同步功能,同步APP数据时会上传所有沙盒数据。如果没有按照规范创建目录,会导致大量缓存文件被上传到iCloud,严重占用用户iCloud 空间,严重时甚至会被Apple官方警告。如果将数据写入这些目录,但是又不希望同步到iCloud,iOS提供了API可以排除默认同步的目录,需要开发者在创建文件时主动设置。
由于无法查看iCloud备份的沙盒文件内容,使用Mac本地备份的方式模拟iCloud备份行为。iPhone连接Mac,打开访达,选择将数据备份到Mac,恢复备份。测试发现Document文件夹下的子目录和子文件,属性被设置为NSURLIsExcludedFromBackupKey,恢复备份后不在,符合预期。不过用电脑备份和iCloud有个差异,Library/Caches下的文件也会被备份。
注意:此方法对于在App Store的应用,即使在恢复备份前将APP删除,也会在恢复备份后自动下载APP,并且恢复数据。对于不在App Store的应用,比如我们的测试DemoAPP,在恢复备份前不要删除DemoAPP,否则无法查看效果。因为无法下载不在Appstore的APP安装包,所以备份内容也无法还原。测试APP在恢复备份后重新安装就可以查看完整的沙盒文件。
-
API设置对于性能的损耗:
iPhone12 :总计 14780 个文件,总计耗时 1124.180794 ms,平均每次耗时0.076ms
iPhone6p:总计 11650 个文件,总计耗时 3730.319023 ms,平均每次耗时0.32ms -
NSURLIsExcludedFromBackupKey不需要每次使用目录或文件时都调用,只需要设置一次即可。设置属性后,该目录下所有子目录和文件都不会同步到iCloud,但是子目录和文件的属性NSURLIsExcludedFromBackupKey依旧为NO。
-
创建文件URL时需要调用[NSURL fileURLWithPath:] ,然后获取和设置 NSURLIsExcludedFromBackupKey。
NSURL *pathurl = [NSURL fileURLWithPath:path];
BOOL success = NO;
success = [pathurl setResourceValue:@(YES) forKey:NSURLIsExcludedFromBackupKey error:nil];
2.4 磁盘大小计算方式
在系统中可以查看一个APP占用磁盘大小,iPhone 存储空间通常由APP 大小和文稿数据大小组成。getResourceValue:forKey:error: 或者attributesOfItemAtPath:error: 直接获取的是“文件大小”,不是文件占用的磁盘物理空间。计算文件的磁盘占用大小需要通过磁盘块的方式。标准头文件stat.h的st_blocks可以获取到块的数量,st_blocks * 512计算出文件的磁盘占用大小。 扇区(block)是磁盘读写的最小物理单位。之所以扇区大小是 512 字节,这种做法源自较早的磁盘扇区大小标准。这种设计是基于早期磁盘技术的物理限制,尽管现代硬盘的物理扇区大小可能已经增加到了 4096 字节,但 512 字节的逻辑块大小在许多文件系统和操作系统的接口中仍然被保留。iOS系统存储单位为十进制,且保留有效小数机制为四舍五入。

+ (unsigned long long)fileSizeOnDisk:(nonnull NSString *)filePath {
struct stat fileStat;
int res = stat([filePath cStringUsingEncoding:NSUTF8StringEncoding], &fileStat);
if (-1 == res) {
return 0;}
long long fileSize = fileStat.st_blocks / 8 * fileStat.st_blksize;
return fileSize ;
}
2.5 APP包大小
APP包大小是手机沙盒的重要组成部分,包体积直接影响用户转化率。用户可以在iPhone存储空间设置中查看设备上各APP大小和文稿与数据大小。
百度APP在iOS17系统的iPhone存储空间设置中,系统不显示APP大小,只有文稿与数据大小。经过调研,发现在iOS17系统APP使用ODR功能后,会导致APP大小被计算到了iOS系统数据。推测是iOS17系统BUG,iOS18系统已经恢复正常。
03 磁盘清理
在综合性 APP 的开发中,多个业务方共同使用沙盒空间,磁盘缓存的管理面临诸多挑战。每个业务方对磁盘使用的整体感知较弱,难以准确评估自身的空间占用大小是否合理,磁盘占用很容易出现无限增长的问题。同时,不同业务方可能独立设计了缓存清理策略,缺乏统一规范,难以满足统一管理的需求。
为解决这些问题,从全局出发设计一套高效的磁盘清理方案。这套方案结合自动清理与手动清理的机制,对磁盘使用进行统一管理。自动清理负责监测磁盘占用情况,通过设置清理阈值和判断条件,在空间不足时通知或触发业务方执行清理操作。清理范围以业务缓存为主,支持按业务个性化配置清理规则,确保管理灵活高效。手动清理则面向用户,提供简单直观的操作界面,允许用户自主选择清理范围,管理下载文件等数据,从而平衡自动化与用户自主权。
此外,在iOS平台上,系统本身具有定期清理临时文件和部分缓存内容的机制。设计磁盘清理方案时,合理利用这些系统行为,同时避免依赖其不可控性。通过以上策略,可以在确保磁盘空间高效管理的同时,最大限度地保障用户体验,为综合性APP提供可靠的存储管理支持。

3.1 自助清理
3.1.1 业务限额
为了管理和规范业务方对磁盘的使用,根据业务的使用场景和必要性,评估每个业务方需要使用的磁盘空间,每一个业务占用的缓存大小会被分配一个限额,业务需要保证自身缓存占用限制在限额以下。业务方从磁盘组件获取业务自身限额值,保证自身缓存占用在限额以内;而磁盘组件会从磁盘剩余大小、APP已使用大小、业务使用频率等条件实时分配合适的限额给各个业务方。
3.1.2 磁盘等级
根据设备的剩余磁盘空间与应用程序所占用的磁盘空间大小,我们可以将磁盘状态细分 为Normal、Warning、以及Critical三个等级,每个等级都反映了用户磁盘空间的使用状况。当处于Normal时,表明用户的手机尚拥有充裕的剩余空间,且APP所占用的磁盘空间相对较小。在此情境下,我们可以适度增加分配给各个业务方的限额,使得业务方有机会缓存更多内容,从而实现以空间换取时间的性能优化,进一步提升用户体验。
然而,一旦进入Critical等级,意味着用户的手机剩余空间已所剩无几,或是 APP占用了过多的空间。这种情况下,用户的手机很容易出现卡顿现象,甚至面临存储空间告急的困境。更为严重的是,这可能会迫使用户做出卸载APP的极端选择。因此,在Critical等级下,我们必须对业务方使用磁盘空间的行为进行严格限制,并强制要求业务方彻底清理任何不必要的缓存,以确保用户的手机能够维持基本的运行需求。
3.1.3 状态检测
磁盘状态检测是磁盘组件的核心功能,检测 APP 运行期间设备磁盘的使用情况,判断是否需要触发自动清理操作。APP 启动后周期性的执行磁盘使用状态检查,自动触发相应的清理机制。通过不同条件触发磁盘清理,以优化应用性能并提升用户体验。为此设计了多种触发清理机制的机制,确保不同情况下都能触发清理操作:
等级:根据磁盘使用等级的变化来决定是否清理;
版本:如果应用版本发生升级,会强制业务方执行一次清理。 时间:根据磁盘等级设定兜底的定期清理间隔。
3.1.4 触发清理
业务方在各自的组件中注册磁盘清理回调protocol,不同的业务模块能够响应磁盘等级变化并进行相应的处理,实现了磁盘清理服务与业务模块之间的解耦合。业务在收到磁盘状态等级变化时,重新查询业务限额,并调整自身策略,管控和优化自身占用缓存,保证保证自身缓存占用在限额以内。
磁盘组件会逐一调用各业务模块注册的清理回调,通过protocol抽象各模块的清理逻辑,实现了对多业务模块的统一管理和扩展性支持。结合信号量机制实现同步等待,确保每个模块的清理任务按顺序完成。所有清理任务完成后,磁盘组件会触发全局回调进行状态更新。
3.2 手动清理
手动清理沿用自动清理的设计思路,业务方实现清理协议,注册到磁盘组件,然后由磁盘组件统一管控。和自动清理不同的是,手动清理提供了一个用户可视化页面,并且详细列出可清理的内容供用户选择。支持深度清理,在大多数情况下,业务逻辑要求清除所有缓存数据。除此之外,还另外添加了用户资产管理功能。
3.2.1 用户资产管理
用户资产定义为用户自主下载并保存的各类文件,包括但不限于视频、图片、安装包、PDF 文档、Excel 表格以及 Word 文件等。百度APP是一个综合性 APP ,兼具浏览器的功能。用户在浏览网页的过程中,会下载各种内容。特别是在 iOS 设备上,用户还可能会下载一些无法安装的安装包。尽管这些文件是用户主动下载的,但实际上它们可能并无实际用途,且长期占用用户的磁盘空间。用户资产管理模块可以帮助用户轻松地识别并清理那些不再需要或无效的用户资产,从而有效释放存储空间,提升设备的整体性能。
3.3 系统缓存清理
3.3.1 tmp目录
iOS的tmp目录是系统缓存目录,Apple官方文档的说明是使用此目录写入不需要在APP启动之间保留的临时文件。当不再需要文件时,APP应从该目录中删除这些文件,系统也可能会在APP未使用时清除此目录。实际使用过程中发现,依赖系统清理该文件夹具有不可控性,因此需要对该文件夹进行清理,tmp目录主要包含以下文件:

1. 下载缓存文件
NSURLSessionDownloadTask进行文件下载的过程中,系统为了确保数据的完整性和安全性,会在文件下载完成前,将其暂时保存在以.tmp为扩展名的临时文件中。这些临时文件的命名遵循CFNetworkDownload_xxxx.tmp的格式,其中CFNetworkDownload_是固定的前缀,而后续的xxxx部分则根据每个下载任务的不同而有所区别。
NSURLSessionConfiguration配置会导致这些临时文件被存储在沙盒的不同位置。defaultSessionConfiguration创建的下载任务,其临时文件会被保存在沙盒的tmp文件夹内。backgroundSessionConfiguration,临时文件的存储位置则有所不同。在后台下载模式下,为确保即使应用进入后台,下载任务也能继续进行。这些文件会存放在Library/Caches/com.apple.nsurlsessiond/Downloads/<bundle_id>。
然而,需要注意的是,沙盒中的tmp文件夹主要用于存放临时文件,这些文件在磁盘空间不足时可能会被系统自动清理。因此,如果下载任务被取消,且临时文件没有被及时移动到其他安全的存储位置,它们可能会因为 tmp 文件夹的清理机制而被删除。这将导致用户无法从上次中断的位置继续下载,即无法实现断点续传。
2. tmp目录清理
统计tmp目录下可以被清理的文件,可以选择全部清理,也可以按照业务实际应用场景,选择过期清理等方案。
/// 统计 /tmp 目录下需要清理的缓存文件
+ (NSArray<NSURL *> *)calculateTmpSysCache {
// 匹配文件名的模式
NSArray *regexPatterns = @[@"CFNetworkDownload", @"WKWebFileUpload", @"NSIRD_", @"正在存储文稿"];
NSString *tmpPath = NSTemporaryDirectory();
if (!tmpPath) return @[];
NSMutableArray *tmpNeedCleanCache = [NSMutableArray array];
NSFileManager *fileManager = [NSFileManager defaultManager];
for (NSString *fileName in [fileManager enumeratorAtPath:tmpPath]) {
NSString *fullPath = [tmpPath stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:fullPath];
// 检查是否符合清理条件
if ([self shouldCleanFile:fullPath patterns:regexPatterns]) {[tmpNeedCleanCache addObject:fileURL];}}
return tmpNeedCleanCache;
}
3.3.2 WKWebView清理
WKWebView是iOS和MacOS上用于加载和展示网页内容的控件,它利用了多种缓存机制来提升加载速度和用户体验。以下是WKWebView缓存产生的几个主要原因:
-
资源缓存(HTTP 缓存):WKWebView会缓存通过网络请求加载的网页资源(如 HTML、CSS、JS、图片等),以减少重复下载,提升网页的加载速度。这些资源通常存储在本地磁盘上。
-
Cookie 缓存:网站使用的Cookie会被WKWebView缓存,用于维护会话状态、用户登录信息等。
-
Session Storage和Local Storage:WKWebView支持HTML5的sessionStorage和localStorage,用于本地存储网站数据,以便后续访问时能够直接从缓存中读取,而无需重新下载。
-
WebKit Cache(WebKit内部缓存):WebKit内部有一套复杂的缓存系统,用于管理各种网页资源、脚本、图像等的缓存。WKWebView依赖这些机制来加速网页内容加载。
-
Service Workers和离线缓存:一些网页使用Service Workers来实现离线功能或加速加载特定资源,WKWebView会缓存这些资源,以便在后续使用时能够从本地获取。
1. WKWebView缓存清理方法
清理指定数据类型的缓存:通过WKWebsiteDataStore可以清理特定类型的缓存,比如Cookies、缓存、localStorage等。该方法可以清理指定类型的缓存数据,并支持自定义时间范围。以下代码展示了如何清理WKWebView的缓存数据:
// 获取所有类型的缓存
NSSet *websiteDataTypes = [NSSet setWithArray:@[
WKWebsiteDataTypeCookies, // Cookie
WKWebsiteDataTypeLocalStorage, // localStorage
WKWebsiteDataTypeIndexedDBDatabases, // IndexedDB
WKWebsiteDataTypeWebSQLDatabases, // WebSQL
WKWebsiteDataTypeFetchCache, // Fetch API
WKWebsiteDataTypeDiskCache, // 磁盘缓存
WKWebsiteDataTypeMemoryCache, // 内存缓存
WKWebsiteDataTypeOfflineWebApplicationCache // 离线应用缓存
]];
// 获取过去时间的日期,比如一个月前
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
// 清理特定类型的数据
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypesmodifiedSince:dateFromcompletionHandler:^{
NSLog(@"清理缓存完成");
}];
清理指定域名的数据如果只想清理某个特定网站的缓存,可以通过查询 WKWebsiteDataRecord 来实现:
// 获取指定域名的数据
[[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
for (WKWebsiteDataRecord *record in records) {
if ([record.displayName containsString:@"example.com"]) { // 指定域名[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypesforDataRecords:@[record]completionHandler:^{
NSLog(@"清理 %@ 的缓存完成", record.displayName);}];}}
}];
2. WKWebView清理实践
在WKWebView的清理实践中,先计算NetworkCache文件夹的大小,一旦超过设定的限制即会触发清理流程。在清理过程中,为了保证缓存带来的性能优化和磁盘空间占用达到平衡,我们并没有选择全部删WKWebView的所有缓存,而是按照文件的修改日期进行排序,确保最老的文件在后续的清理中会被优先处理。
+ (void)cleanUpWKWebViewCacheWithLimit {dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC * SOME_DELAY)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 设置缓存上限为10MB
unsigned long long cacheLimit = SOME_CACHE_LIMIT;
// 获取WebKit网络缓存目录
NSString *networkCachePath = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Caches/WebKit/NetworkCache"];
// 计算缓存总大小
unsigned long long totalSize = [self calculateDirectorySize:networkCachePath];
if (totalSize < cacheDiskLimit) {
return;}
// 获取Records子目录路径
NSString *networkCacheRecordsPath = [networkCachePath stringByAppendingPathComponent:@"/Version 16/Records"];
// 获取所有文件列表,安时间排序判断需要清理的文件
NSArray *filelist = [self listFilesInDirectory:networkCacheRecordsPath];
if (filelist.count == 0) {
return;}
if (@available(iOS 9.0, *)) {
dispatch_async(dispatch_get_main_queue(), ^{
WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore];
NSSet *dataTypes = [NSSet setWithArray:@[WKWebsiteDataTypeDiskCache]];[dataStore removeDataOfTypes:dataTypes modifiedSince:SOME_DAY_AGO completionHandler:^{
// 清理完成}];});}});
}
3.3.3 dyld缓存清理
dyld是iOS和MacOS系统中的一个关键组件,负责在程序启动时加载和链接动态库(如框架和共享库)。在iOS 13及更早版本中,dyld可能会在tmp目录下创建一些临时缓存文件,用于加速后续的程序启动过程。这些缓存文件包含了动态库的加载信息,使得系统在下次启动相同程序时能够更快地找到并加载所需的库。
然而,iOS13系统之前会在每次APP升级后的首次启动生成一个新的dyld缓存,保存在tmp/com.apple.dyld,并且之前的APP版本的dyld缓存也不会自动删除。该部分缓存会随着版本升级不断累加,需要管理这部分缓存,实际上还有部分用户从 iOS13 系统升级到更高系统,这部分缓存就会一直遗留在用户手机中,高达上百 MB。iOS14 系统则是迁移到了Library/Caches/com.apple.dyld,且系统会自动清理。
/// 清理iOS13系统生成的tmp/com.apple.dyld缓存文件
+ (void)cleanTmpDyld {
NSString *tmpDyldPath = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp/com.apple.dyld"];
if ([[NSFileManager defaultManager] fileExistsAtPath:tmpDyldPath]) {
// 系统版本大于iOS14
if (@available(iOS 14.0, *)) {[PFMDiskSizeUtils cleanupDirectoryAtPath:tmpDyldPath];} else {
// 保留计数限制为 1,保留最新的[PFMDiskSizeUtils cleanDiskCaches:tmpDyldPath reservedCountLimit:1];}}
}
3.3.4 其他系统缓存清理
-
Documents/Inbox是iOS应用接收文件的默认目录,直接清理即可;
-
Library/Preferences目录下属于应用的临时 .plist 文件。这些文件通常由 NSUserDefaults自动生成,有时在写入或更新过程中会生成临时文件。
/// 清除 Documents/Inbox 目录
+ (void)cleanUpInboxPath {
NSString *inboxPath = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/Inbox"];
if (inboxPath) {[PFMDiskSizeUtils cleanupDirectoryAtPath:inboxPath];}
}
/// 清除 Library/Preferences/bundleId.plist.xxxx文件
+ (void)cleanUpUserDefaultsTempPlistFiles {
NSString *preferencesPath = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Preferences"];
NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:preferencesPath];
NSString *deleteFilePrefix = [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:@".plist."];
NSString *file;
while (file = [dirEnumerator nextObject]) {
if ([file hasPrefix:deleteFilePrefix]) {
NSString *deleteFilePath = [preferencesPath stringByAppendingPathComponent:file];
NSDate *fileModifyDate = [[[NSFileManager defaultManager] attributesOfItemAtPath:deleteFilePath error:nil] objectForKey:NSFileModificationDate ];[PFMDiskSizeUtils cleanupDirectoryAtPath:deleteFilePath];}}
}
04 总结
本篇文章围绕百度APP的磁盘清理问题,从iOS沙盒文件存储机制出发,系统性地阐述了磁盘管理的重要性和技术实现。文章探讨了自动清理与手动清理的结合策略,通过多维度触发机制和灵活的用户交互设计,平衡了系统性能与用户体验。后续我们还会分享磁盘监控和磁盘异常问题治理相关的文章。
————END————
推荐阅读
读友好的缓存淘汰算法
如何定量分析 Llama 3,大模型系统工程师视角的 Transformer 架构
微服务架构革新:百度Jarvis2.0与云原生技术的力量
技术路线速通!用飞桨让京剧人物照片动起来
无需业务改造,一套数据库满足 OLTP 和 OLAP,GaiaDB 发布并行查询能力
相关文章:
百度APP iOS端磁盘优化实践(上)
01 概览 在APP的开发中,磁盘管理已成为不可忽视的部分。随着功能的复杂化和数据量的快速增长,如何高效管理磁盘空间直接关系到用户体验和APP性能。本文将结合磁盘管理的实践经验,详细介绍iOS沙盒环境下的文件存储规范,探讨业务缓…...
qml Dialog详解
1、概述 Dialog是QML(Qt Modeling Language)中用于显示对话框的组件,它提供了一个模态窗口,通常用于与用户进行重要交互,如确认操作、输入信息或显示警告等。Dialog组件具有灵活的布局和样式选项,可以轻松…...
2025年的校招管理系统会全面实现智能化吗?
随着科技的不断进步,企业的招聘方式也在不断地演变。特别是在校园招聘领域,传统的招聘方法已经难以满足现代企业的需求。2025年的校招管理系统是否会全面实现智能化?这是一个值得探讨的话题。 想象一下,每年的校招季,…...
【Unity】使用Canvas Group改变UI的透明度
目录 一、前言二、Canvas Group三、结合DOTween达到画面淡进的效果 一、前言 在平时开发中,可以通过控制材质、Color改变UI透明度,除此之外还可以CanvasGroup组件来控制透明度。 二、Canvas Group 官方文档链接👉👉 点击进入 …...
2024年博客之星主题创作|2024年度感想与新技术Redis学习
Redis工具深入了解 1.引言与感想2.Redis工具了解2.分布式系统了解2.1单机架构2.2分布式是什么2.3应用服务和数据库服务分离2.4引入更多的应用服务器2.5理解负载均衡器2.6数据库读写分离2.7引入缓存2.8数据库分库分表2.9引入微服务2.10分布式系统小结 1.引言与感想 2024学习了很…...
6. 马科维茨资产组合模型+政策意图AI金融智能体(DeepSeek-V3)增强方案(理论+Python实战)
目录 0. 承前1. 幻方量化 & DeepSeek1.1 What is 幻方量化1.2 What is DeepSeek 2. 重写AI金融智能体函数3. 汇总代码4. 反思4.1 不足之处4.2 提升思路 5. 启后 0. 承前 本篇博文是对上一篇文章,链接: 5. 马科维茨资产组合模型政策意图AI金融智能体(Qwen-Max)增…...
Unity自学之旅05
Unity自学之旅05 Unity学习之旅⑤📝 AI基础与敌人行为🥊 AI导航理论知识(基础)开始实践 🎃 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 🤗 总结归纳 Unity学习之旅⑤ 📝 AI基础与敌…...
linux中关闭服务的开机自启动
引言 systemctl 是 Linux 系统中用于管理 systemd 服务的命令行工具。它可以用来启动、停止、重启服务,管理服务的开机自启动,以及查看服务的状态等。 什么是 systemd? systemd 是现代 Linux 发行版中默认的 初始化系统(init sys…...
Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )
一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化: 文件是存储数据的一种非常基本且重要的方式。通过文件,我们可 以将程序运行时产生的数据永久保存下来,以便将来使用。 跨平台兼容性: 文件是一种通用…...
ubuntu黑屏问题解决
重启Ubuntu后,系统自动进入tty1,无法进入桌面。想到前几天安装了一些主题之类的,然后今天才重启,可能是这些主题造成冲突或者问题了把。 这里直接重新安装ubuntu-desktop解决: 更新源: sudo apt-get upd…...
Java如何实现反转义
Java如何实现反转义 前提 最近做的一个需求,是热搜词增加换一批的功能。功能做完自测后,交给了测试伙伴,但是测试第二天后就提了一个bug,出现了未知词 levis。第一眼看着像公司售卖的一个品牌-李维斯。然后再扒前人写的代码&…...
动态规划(路径问题)
62. 不同路径 62. 不同路径 - 力扣(LeetCode) 动态规划思想第一步:描述状态~ dp[i][j]:表示走到i,j位置时,一共有多少种方法~ 动态规划思想第二步:状态转移方程~ 动态规划思想第三步…...
python http调用视觉模型moondream
目录 一、什么是moondream 二、资源地址 三、封装了http进行接口请求 四、代码解析 解释 可能的改进 一、什么是moondream Moondream 是一个针对视觉生成任务的深度学习模型,专注于图像理解和生成,包括图像标注(captioning)、问题回答(Visual Question Answering,…...
Spark Streaming编程基础
文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用,查看结果 2. 编程模型的基本概念3…...
深入 Flutter 和 Compose 的 PlatformView 实现对比,它们是如何接入平台控件
在上一篇《深入 Flutter 和 Compose 在 UI 渲染刷新时 Diff 实现对比》发布之后,收到了大佬的“催稿”,想了解下 Flutter 和 Compose 在 PlatformView 实现上的对比,恰好过去写过不少 Flutter 上对于 PlatformView 的实现,这次恰好…...
C# OpenCV机器视觉:红外体温检测
在一个骄阳似火的夏日,全球却被一场突如其来的疫情阴霾笼罩。阿强所在的小镇,平日里熙熙攘攘的街道变得冷冷清清,人们戴着口罩,行色匆匆,眼神中满是对病毒的恐惧。阿强作为镇上小有名气的科技达人,看着这一…...
FCA-FineDataLink认证
FCA-FineDataLink证书 Part.1:判断题 (总分:18分 得分:16) 第1题 判断题 数据同步只支持写入到已存在表,不支持自动建表(得分:2分 满分:2分) 正确答案:B 你的答案&…...
第19篇:python高级编程进阶:使用Flask进行Web开发
第19篇:python高级编程进阶:使用Flask进行Web开发 内容简介 在第18篇文章中,我们介绍了Web开发的基础知识,并使用Flask框架构建了一个简单的Web应用。本篇文章将深入探讨Flask的高级功能,涵盖模板引擎(Ji…...
js截取video视频某一帧为图片
1.代码如下 <template><div class"box"><div class"video-box"><video controls ref"videoRef" preload"true"src"https://qt-minio.ictshop.com.cn:9000/resource-management/2025/01/08/7b96ac9d957c45a…...
[云讷科技]Kerloud Falcon四旋翼飞车虚拟仿真空间发布
虚拟仿真环境作为一个独立的专有软件包提供给我们的客户,用于帮助用户在实际测试之前验证自身的代码,并通过在仿真引擎中添加新的场景来探索新的飞行驾驶功能。 环境要求 由于环境依赖关系,虚拟仿真只能运行在装有Ubuntu 18.04的Intel-64位…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
