Core Data 关系约束未体现在 CloudKit schema 中,是否正常?
结论
这是预期行为。NSPersistentCloudKitContainer 支持同步 Core Data 原生关系,但 CloudKit schema 不会完整复刻 .xcdatamodeld 中的关系和约束。仅凭控制台中没有关系连线或外键约束,不能判断配置有误。
对于普通的 1
、n 关联,可以继续使用 Core Data relationship,无须为了同步而手动保存关联 UUID 或创建中间实体。Core Data 负责将关系转换为云端记录。Apple 的关系映射说明原问题没有提供模型配置或同步错误日志,暂时无法确认当前项目的关系是否已正常同步。
关系在 CloudKit 中如何表示?
Core Data 管理生成的 CloudKit schema,使用自己的方式编码关系,不使用 CKRecord.Reference 存储这些关系。
| Core Data 关系 | CloudKit 中的表示方式 |
|---|---|
| 1 | 两端记录分别通过字段保存对方的 recordName |
| 1 | 在“多”的一侧保存指向“一”的一侧的 recordName |
| n | 通过额外的 CDMR(Core Data Mirrored Relationship)记录保存关联 |
例如,当 Post.attachments 和 Attachment.post 互为 inverse 时,CD_Attachment 记录中的 CD_post 字段保存所属 Post 的记录名称;CD_Post 不需要再保存一份附件列表。
对于 Post.tags 和 Tag.posts,关联信息保存在 CDMR 记录中,只查看 CD_Post 和 CD_Tag 的字段可能看不到该 n
应如何配置模型和修改关系?
先检查参与 CloudKit 同步的模型是否符合以下要求:
- 所有 relationship 都设为 Optional。
- 每个 relationship 都配置 inverse。
- 不使用实体的 Unique Constraints。
- 不使用
Deny删除规则。 - 同一 configuration 中的实体不关联其他 configuration 中的实体。
这些都是 Apple 列出的兼容性要求。同步模型要求关系设为 Optional;如果业务上必须有关联,可以在应用操作中检查。CloudKit 模型限制
模型配置正确后,可以直接操作 managed object 的关系。下面的代码假设模型已经生成 Post、Attachment、Tag 类,且上述 inverse 均已配置:
import CoreData
// 在 context 的队列中调用,三个对象均属于该 context。
func link(
attachment: Attachment,
post: Post,
tag: Tag,
in context: NSManagedObjectContext
) throws {
attachment.post = post
post.mutableSetValue(forKey: "tags").add(tag)
try context.save()
}
代码直接建立 1
和 n 关系。Core Data 会维护已配置的 inverse,无须再向另一端手动写入 UUID。Core Data 的关系维护机制context.save() 保存的是本地更改,并不表示其他设备已经收到数据。
数据完整性需要应用处理到什么程度?
Core Data 负责关系管理和同步映射。“每个项目必须至少有一名成员”“某个业务编号不能重复”等规则,仍需要应用设计校验与冲突处理。
Apple 指出,关系变更可能因操作大小限制而无法原子保存,相关记录也可能乱序同步。因此,应用应能暂时处理缺失的关联对象,避免一看到空关系就删除数据或认定记录损坏。关系同步的限制
可以根据业务需要采取以下措施:
- 在用户提交操作前检查必填关联、数量限制等规则,并尽量在一次本地保存中完成相关修改。
- 为同步后的重复记录或业务冲突制定确定的处理规则,修复操作应可重复执行。
- 验证多设备离线修改、重新联网、删除与编辑同时发生时的行为。
单设备保存前的检查无法保证多台离线设备之间的全局唯一性。如果业务要求在提交时获得严格的跨设备约束保证,需要额外设计能够协调写入的服务端机制,仅靠模型选项无法实现。
还需要自定义 UUID 或中间实体吗?
自定义 UUID 可以用于业务标识、导入导出或对外接口,但原生关系同步不要求使用自定义 UUID,它也不会自动提供唯一性保证。
普通 n
关系可以直接建模。如果关联本身还要保存额外信息,例如成员加入时间、角色或排序值,才有必要把关联建成独立实体。排查当前项目时,先确认 store 加载时没有模型兼容性错误,再创建一组实际关联的数据,检查另一台设备导入后能否通过 Core Data relationship 读取。应以对象及关系是否正确同步来判断,不能只看 CloudKit schema 的外观。
备注:内容仅供参考。
