What's new in Core Data
System & Services 进阶 20m

Core Data 的新功能

What's new in Core Data

2023年6月5日

在 Apple 官方观看视频

一句话判断

Composite Attributes 让你终于可以用结构化的方式在 Core Data 中存储复杂类型,而不再依赖 Transformable 的黑盒序列化——而且还能在 NSPredicate 中用命名空间键路径查询。如果你之前因为 Transformable 的局限性而绕开 Core Data,现在值得重新评估。

这场 Session 讲了什么

Session 介绍了 Core Data 在 2023 年的三项重要更新。

1. Composite Attributes(组合属性)

  • 新的属性类型 NSCompositeAttributeDescription,允许在单一属性中封装复杂结构。
  • 由多个内置类型属性(String、Float、Int、Data 等)组成。
  • 支持嵌套——一个 Composite Attribute 可以包含另一个 Composite Attribute。
  • Xcode Core Data 模型编辑器已更新支持定义和管理。
  • 在代码中通过 Dictionary<String, Any> 类型访问。
  • 支持 NSFetchRequest 和 NSPredicate 查询——用命名空间键路径(如 colorScheme.primary)做过滤。

Composite Attributes vs Transformable

  • Transformable:需要自定义转换器,不支持查询,黑盒存储。
  • Composite Attributes:无需转换代码,支持查询,结构化存储。

性能优势:如果两个实体之间有一对一关系且几乎总是一起访问,可以把关系替换为 Composite Attribute——避免跨关系的 faulting 开销。

2. Staged Migrations(分阶段迁移)

  • 当数据模型变更超出 Lightweight Migration 的能力时,可以将变更分解为多个步骤。
  • 每个步骤都是 Lightweight Migration 兼容的变更。
  • Core Data 按序执行每个阶段,App 在每个阶段之间获得执行控制权。
  • 可以替代数千行的自定义迁移代码。

3. Deferred Migration(延迟迁移)

  • 将模型迁移推迟到不阻塞 UI 的时机执行。
  • 保持 App 响应性。

值得深挖的点

Composite Attributes 的查询能力是它区别于 Transformable 的核心优势。Transformable 属性对 Core Data 来说是不透明的二进制数据——你不能在 fetch request 中过滤 Transformable 属性的内容。Composite Attributes 的每个元素都有独立的键路径,可以用 NSPredicate(format: "colorScheme.primary = %@", "red") 这样的查询直接过滤。这对需要按内部字段搜索的场景(如按地址的邮编搜索)非常有价值。

用 Composite Attribute 替代一对一关系的性能优化值得评估。如果你有一个 Aircraft 实体和一个 ColorScheme 实体,每次加载 Aircraft 几乎都要访问 ColorScheme,那么把 ColorScheme 做成 Composite Attribute 嵌入 Aircraft 可以避免 faulting——Core Data 不需要额外加载一个关联对象,所有数据在一个实体中。

Staged Migration 的分解策略把复杂的不可自动迁移的变更转化为一系列可自动迁移的小步骤。比如”从一个实体拆分出新实体并保留数据”这种复杂操作,可以分解为:先添加新实体 → 再迁移数据 → 最后删除旧字段。每一步都是 Lightweight Migration 可以处理的。

代码片段

定义和使用 Composite Attributes:

// 在 Xcode Core Data 模型编辑器中定义:
// Composite Attribute: colorScheme
//   - primary: String
//   - secondary: String
//   - tertiary: String

// 在 Aircraft 实体中使用
@NSManaged var colorScheme: [String: Any]

// 设置值
aircraft.colorScheme = [
    "primary": "红色",
    "secondary": "白色",
    "tertiary": "蓝色"
]

// 使用命名空间键路径查询
let request = NSFetchRequest<Aircraft>(entityName: "Aircraft")
request.predicate = NSPredicate(
    format: "colorScheme.primary = %@", "红色"
)
// 可以直接按 Composite Attribute 的内部字段过滤!

Staged Migration 的基本结构:

// 定义迁移阶段序列
// 每个阶段是一个 Lightweight Migration 兼容的模型变更

// 阶段1:添加新实体 FlightData
// - 添加 FlightData 实体
// - 添加 Aircraft 到 FlightData 的关系

// 阶段2:迁移现有数据到新实体
// - 将 Aircraft.flightData 中的二进制数据解析并创建 FlightData 记录

// 阶段3:清理旧字段
// - 移除 Aircraft.flightData 属性

// Core Data 按序执行每个阶段
// App 在阶段之间获得执行控制权

最佳实践

  • 评估现有的 Transformable 属性,看是否可以用 Composite Attributes 替代——如果需要查询内部字段,必须替换。
  • 频繁一起访问的一对一关系考虑替换为 Composite Attribute 以减少 faulting 开销。
  • Composite Attributes 的 elements 数组不能包含 NSRelationshipDescription——它只支持属性,不支持关系。
  • 访问 Composite Attribute 值时使用字典语法,注意类型安全(Any 类型需要手动转换)。
  • 复杂数据模型迁移使用 Staged Migration 分解为小步骤,避免写大量自定义迁移代码。
  • 大型数据集的迁移使用 Deferred Migration,避免阻塞 App 启动。

还有什么值得关注

  • “Evolve your app’s schema”(WWDC22)详细介绍了 Lightweight Migration。
  • Composite Attributes 的嵌套能力意味着你可以创建多层级的结构化数据。
  • Staged Migration 可能需要你重新审视数据模型的版本历史和变更策略。
  • Deferred Migration 对大型 App 的启动体验改善明显——用户不需要等迁移完成。
  • Xcode 的 Core Data 模型编辑器已更新,方便可视化编辑 Composite Attributes。
WWDC 2023