Documents Directory — 是 iOS应用程序沙箱中的目录,用于存储用户数据,这些数据应在应用程序会话之间保持并通过iTunes File Sharing和iCloud对用户可用。根据Apple File System Programming Guide(2024),该目录的内容会自动包含在iCloud和iTunes备份中,因此开发者应有意识地选择在Documents中存储哪些数据。与Caches Directory不同,Documents中的文件不会在空间不足时被系统删除 — 大小管理的责任属于应用程序。
主要内容
Documents Directory — 是 iOS应用程序沙箱内的目录,用于存储用户数据,这些数据应在启动之间保持并对用户可用。每个应用程序都有自己的独立沙箱,而Documents是与Caches、tmp和Library并列的关键目录之一。
iOS使用严格的沙箱(sandbox):应用程序未经特殊授权无法访问其他应用程序的文件系统和系统目录。Documents Directory — 唯一一个用户可通过iTunes File Sharing查看其内容的目录(在Info.plist中启用相应的UIFileSharingEnabled开关时)。
根据Apple WWDC 2023的数据,App Store中超过85%的应用程序使用Documents Directory存储至少一种用户数据 — 从导出的PDF到保存的游戏文件和导出的图片。
开发者必须理解:Documents中的文件会自动包含在iCloud和iTunes备份中。如果应用程序在Documents中存储大量可恢复的数据(例如,图片缓存或临时文件),这将导致用户iCloud存储空间的不必要占用。
在Swift中,Documents Directory的路径通过FileManager获取。Apple建议使用基于URL的API而非基于字符串的API,以便与iOS现代功能更好地兼容。
import Foundation
let fileManager = FileManager.default
guard let documentsURL = fileManager.urls(
for: .documentDirectory,
in: .userDomainMask
).first else { return }
// 在Documents中创建文件
let fileURL = documentsURL.appendingPathComponent("report.pdf")
let data = Data("Hello, world!".utf8)
try data.write(to: fileURL)
Objective-C使用NSSearchPathForDirectoriesInDomains — 一种较旧但仍受支持的方法,它返回字符串路径而非URL。
@import Foundation;
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES
);
NSString *documentsPath = paths.firstObject;
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"report.pdf"];
Swift中的现代项目应使用FileManager.urls,因为该方法返回URL而非字符串,这减少了路径编码错误的风险,并使代码更具类型安全。
Documents Directory用于存储用户创建的或用户明确需要的数据。Apple划分了几种适合该目录的类别。
用户创建或导入的文件 — 文本文档、PDF、图片、导出的报告、备份文件。这些数据对用户具有直接价值,丢失它们将是致关重要的。
游戏保存、应用程序状态文件、导出的项目 — 用户期望在重新安装应用程序后恢复的所有内容。但是,对于关键数据,建议额外使用iCloud Key-Value Storage或具有iCloud同步功能的Core Data。
| 数据类型 | 适合Documents | 替代方案 |
|---|---|---|
| PDF和文本文档 | 是 | — |
| 图片缓存 | 否 | Caches Directory |
| 游戏保存 | 是 | iCloud KVS |
| 日志和调试数据 | 否 | Caches或tmp |
| 导出的报告 | 是 | — |
关键标准:如果数据可以从网络恢复或重新创建 — 它们应放在Caches中,而非Documents。Documents中的每一个吉字节都是用户iCloud备份中的一个吉字节。
iOS在设备连接到iTunes或与iCloud同步时会自动将Documents Directory的内容包含在备份中。这种行为无法在目录级别取消 — 只能通过NSURLIsExcludedFromBackupKey属性按文件单独设置。
从iOS 5.0开始,Apple开始拒绝在Documents中存储大量可恢复数据的应用程序。Apple建议:可重新下载的文件应存储在Caches Directory中,并标记为从备份中排除。
import Foundation
let documentsURL = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first!
// 将文件从iCloud备份中排除
var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
var fileURL = documentsURL.appendingPathComponent("cached_data.json")
try fileURL.setResourceValues(resourceValues)
如果应用程序使用iCloud Documents,则iCloud同步通过NSUbiquitousContainer工作。在这种情况下,Documents Directory中的文件会自动在用户设备之间同步。对于没有iCloud的应用程序,同步仅限于备份。
Documents和Caches之间的区别 — 是初学iOS开发者最常见的误解之一。主要区别:系统可以随时删除Caches中的文件以释放空间,但未经用户同意从不动Documents。
| 特征 | Documents Directory | Caches Directory |
|---|---|---|
| iCloud备份 | 是(默认) | 否 |
| 系统删除 | 从不 | 空间不足时 |
| iTunes File Sharing | 是(启用标志时) | 否 |
| 用途 | 用户数据 | 缓存、临时数据 |
| 数据恢复 | 需要恢复 | 可从网络重新下载 |
根据Apple Developer Documentation(2024),不正确使用Documents Directory是应用程序审核被拒的常见原因之一:如果应用程序在Documents中存储超过几兆字节的可恢复数据,Apple建议将它们移到Caches或应用NSURLIsExcludedFromBackupKey。
实用规则:如果用户会因文件丢失而难过 — 存储在Documents中。如果文件可以重新下载或生成 — 存储在Caches中。
经验丰富的iOS开发者总结了几条规则,可以帮助在应用程序生命周期的所有阶段 — 从开发到在App Store发布 — 避免Documents Directory的问题。
定期通过FileManager.enumerator(at:includingPropertiesForKeys:)检查Documents Directory的大小。如果非用户数据的大小超过100 MB — 这是重新考虑存储架构的理由。
对于所有可从网络重新下载的文件,设置isExcludedFromBackup = true。这减少了用户iCloud存储的负担,并降低了应用程序被App Review拒绝的风险。
在更改Documents中的数据格式时,预留迁移机制:在确认新文件已正确创建之前,不要删除旧文件。使用版本特定的子目录。
import Foundation
let documentsURL = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first!
let versionDir = documentsURL.appendingPathComponent("v2")
try FileManager.default.createDirectory(
at: versionDir,
withIntermediateDirectories: true
)
遵守这些实践可以减少用户数据丢失的风险,缩小iCloud备份的大小,并使应用程序更容易通过App Store审核。
常见问题
可以,通过Files — iOS 11以上版本内置的应用程序。当在Info.plist中启用UIFileSharingEnabled开关时,Documents Directory的内容将显示在文件应用程序的“我的iPhone”模块中。用户可以浏览、复制和删除文件。
应用程序的整个沙箱,包括Documents Directory、Caches、tmp和Library,会从设备上完全删除。iCloud中的备份会保留到恢复或手动删除。重新安装后,应用程序将从干净的沙箱开始。
使用FileManager.enumerator遍历目录中的所有文件并求和它们的大小。对于每个文件,通过resourceValues(forKeys:)获取.fileSize属性。或者,使用URLResourceKey.fileSizeKey和.directoryEnumerationResults。
默认情况下,Core Data在Library/Application Support中创建sQLite文件,而非Documents中。不建议将数据库迁移到Documents — 它将被包含在iTunes File Sharing中,用户可能意外删除或修改它。例外情况:如果应用程序明确通过Core Data向用户提供数据访问。
UIFileSharingEnabled(Application supports iTunes file sharing) — Info.plist中的布尔开关。设置为YES时,用户可通过iTunes和Files从Documents Directory复制文件。将开关添加到Info.plist:UIFileSharingEnabled = YES。只有在应用程序确实创建用户文档时才启用。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。