Core Data 是 Apple 的数据管理框架,为 iOS、macOS、tvOS 和 watchOS 提供对象关系映射。它自动完成应用中对象的保存、检索和过滤,基于 SQLite、XML 或二进制存储运行。根据 Apple Core Data Documentation,该框架使用 Managed Object Context 和 NSPersistentContainer 概念来管理持久化堆栈。
要点
Core Data — 是一个对象图和持久化管理框架,属于 Cocoa Touch 的一部分。与普遍误解相反,Core Data 不是数据库,而是一个对象管理层,可以使用 SQLite 作为存储之一。Core Data 的主要任务是跟踪对象的变化,管理它们的生命周期,并将状态与磁盘同步。
该框架提供了 对象图,其中每个 Managed Object 由上下文监视变化。当保存上下文时,所有已修改、添加和删除的对象一次事务提交到持久存储中。这使开发者免于编写 SQL 查询和手动管理事务。
根据 Swift Developer Survey(2025)的统计,Core Data 在 52% 的 iOS 应用中使用来处理本地数据。尽管出现了现代替代方案(SwiftData、Realm),Core Data 凭借其成熟度和与系统的深度集成,仍然是现有 Apple 项目中的主要框架。
对于具有中等复杂数据模型、需要对象间关系、更改撤销和通过 faulting 机制自动缓存的项目,请使用 Core Data。
Core Data 的架构围绕 Managed Object Context 概念构建 — 一个跟踪所有对象变化的工作空间。上下文通过内置的 NSUndoManager 支持撤销(undo/redo),这使得可以在不手动保存状态快照的情况下实现草稿和操作取消。当调用 save() 时,上下文在持久存储中以单次事务提交所有更改,保证原子性和数据一致性。
Core Data 的数据模型在 .xcdatamodeld 文件中定义 — Xcode 的可视化编辑器,其中描述所有实体、其属性和关系。编译时,模型序列化为 .momd 并通过 NSManagedObjectModel 加载。
Entity — 是数据类型的描述,类似于 SQL 中的表。每个 Entity 包含一组 Attributes — 带有数据类型(String、Integer、Date、Boolean、Data)的命名字段。与 Room 不同,Core Data 需要通过模型编辑器为每个属性显式选择类型。
Relationship — 实体之间的关系,类似于 SQL 中的外键。Core Data 支持所有类型的关系:一对一、一对多和多对多。每个关系配置 Delete Rule(Cascade、Nullify、Deny)— 删除关联对象时的行为。
| Delete Rule | 删除时的行为 | 应用示例 |
|---|---|---|
| Cascade | 删除所有关联对象 | 删除订单及其项目 |
| Nullify | 置空反向关联 | 删除作者但不删除书籍 |
| Deny | 如果有关联对象则阻止删除 | 防止删除包含产品的分类 |
Delete Rule 的选择对数据完整性至关重要:未经检查的 Cascade 可能会删除三分之一的数据库,而 Deny 可能会以难以理解的错误阻止操作。在生产代码中,建议使用 Nullify 并手动处理孤立记录。
在 Xcode 模型编辑器中,开发者不仅可以设置 Entity 和属性,还可以设置 constraints(唯一性约束)、用于加速查询的索引以及属性的 default values。所有模型更改都编译到 .momd 文件中,该文件在初始化 NSPersistentContainer 时加载。模型版本控制(Model Versioning)允许维护多个模式版本并在它们之间执行迁移。
NSPersistentContainer — 从 iOS 10 和 macOS 10.12 开始管理 Core Data 堆栈的统一对象。它封装了 NSManagedObjectModel、NSPersistentStoreCoordinator 和 NSManagedObjectContext,自动完成模型加载和存储配置。对于较早版本,堆栈是手动构建的,但现在不推荐这样做。
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext — 绑定到主线程的主上下文。所有读取和 UI 更新都通过它进行。为了性能,建议在具有私有队列的子上下文中写入数据然后同步。
NSPersistentStoreCoordinator 协调器将模型与磁盘上的物理存储连接起来。Core Data 支持多种存储类型:SQLite(推荐)、Binary 和 In-Memory。SQLite 存储支持迁移、增量备份和写入过程中的故障恢复。
NSFetchRequest — 描述对 Core Data 存储的查询的对象。它包含实体名称、过滤谓词、排序和检索设置。查询通过 context.fetch() 执行,返回 NSManagedObject 数组。
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = NSPredicate(format: "age >= %d", 18)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
request.fetchLimit = 50
let results = try context.fetch(request)
NSPredicate 支持复杂条件:LIKE、IN、BETWEEN、CONTAINS[c](不区分大小写)、SUBQUERY 用于对相关实体进行嵌套查询。Core Data 还支持 NSFetchedResultsController — 用于在 UITableView 中响应式加载数据的类,它自动跟踪更改并使用动画部分更新表格。
在多线程应用中使用 Core Data 需要严格遵守规则:NSManagedObject 不能在线程之间直接传递。每个线程(或队列)必须使用自己的上下文。主要方法是创建一个具有私有队列(NSPrivateQueueConcurrencyType)的子 NSManagedObjectContext 用于写入,以及用于读取的 viewContext。
子上下文保存到父上下文,然后父上下文保存到磁盘上的存储。这保证了更改不会阻塞主线程,并且 UI 始终通过 mergeChanges 或保存时 viewContext 的自动更新看到一致的状态。
Core Data 使用 faulting — 一种延迟加载相关对象的机制。当获取 User 而不请求其 addresses 时,相关的 Address 不会加载,直到通过点符号访问它们为止。Faulting 节省内存并加速加载,但如果不在后台上下文中控制访问,可能会导致主线程上意外的磁盘访问。
为了高效的多线程处理,使用 NSBatchInsertRequest 和 NSBatchDeleteRequest 进行批量插入和删除,而无需将对象加载到内存中 — 这对于与服务器的数据同步至关重要。
批量操作直接在 NSPersistentStoreCoordinator 级别执行,绕过上下文和对象图。这使得可以在几毫秒内插入 10,000 条记录,而无需在内存中创建 10,000 个 NSManagedObject 实例。执行批量查询后,必须通过 mergeChangesFromContextDidSaveNotification 更新上下文,以便 UI 反映新数据。Apple 建议将批量操作用于初始数据加载和与服务器的夜间同步。
为了跟踪 Core Data 中的更改,使用 NSPersistentHistoryTracking — 一种将每个事务(插入、更新、删除)记录在单独历史中的机制。启用 history tracking 允许在使用同一 SQLite 文件的不同进程和应用之间同步数据,例如主应用和 Notification Service Extension 之间。激活通过带有 persistentHistoryTrackingKey 标志的 NSPersistentStoreDescription 进行,读取通过带有日期和事务类型过滤器的 NSPersistentHistoryChangeRequest 进行。
为了调试和分析 Core Data 性能,使用 macOS 上 Xcode Instruments 套件中的 Core Data Profiler 工具。它显示所有获取、插入、删除和保存操作,以及每个操作的持续时间和在表格和时间线图表中加载的对象数量。开发者可以识别问题区域:多次获取同一查询(缺乏缓存)、滚动表格时的 fault 对象泄漏或由于同步加载相关实体而导致的主线程阻塞。建议在实际设备上进行分析,而不是在模拟器上,因为模拟器的性能不能反映应用在 iPhone 或 iPad 上的真实行为。
常见问题
Core Data — 不是数据库,而是可以使用 SQLite 作为存储的对象管理层。与直接 SQLite 不同,Core Data 跟踪对象更改,管理撤销并提供具有 faulting 和缓存的对象图。SQLite 对查询提供更多控制,但需要编写 SQL 和手动管理事务。
Core Data 支持轻量级迁移(Lightweight Migration)用于非破坏性更改:添加属性、重命名、设置默认值。对于复杂更改,创建 Mapping Model。轻量级迁移通过在 NSPersistentStoreDescription 中设置 shouldMigrateAutomatically 标志启用。
是的,Core Data 通过 @FetchRequest 包装器(用于查询)和 @ObservedObject(用于订阅更改)与 SwiftUI 集成。SwiftUI 在 ManagedObject 更改时自动更新 View,这使得 Core Data 和 SwiftUI 成为用于状态管理的兼容堆栈。
Fault — 是 Core Data 图中的一个轻量级占位符,不包含关联对象的数据。设置 fault(通过 refreshObject:)时,数据从内存中卸载。访问属性时,fault 自动从存储中填充数据 — 这是一种延迟加载机制,优化了内存使用。
测试时使用 In-Memory 存储类型:NSPersistentStoreDescription 与 NSInMemoryStoreType。容器使用测试包中的模型创建。每次测试后,删除所有对象或重新创建容器 — 这保证了测试用例之间的隔离。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。