在 Apple 的持久化技术版图中,Core Data 早已不再是“最新”的那个名字。过去几年里,SwiftData 带来了更现代化的声明式体验;GRDB、SQLiteData 这类方案则让更多开发者重新思考关系型数据库在 Swift 项目中的位置。站在 2026 年回头看,Core Data 既不新,也不轻,甚至在很多代码层面的表现已经明显落后于今天的 Swift。
但这并不意味着它已经失去了价值:如果我们仍然选择 Core Data,那么能不能让它以一种更符合现代 Swift 的方式继续存在下去?
这篇文章不是要为 Core Data 辩护,也不是要说服新的开发者回到 Core Data。它更像是一篇问题整理:在 2026 年,为什么仍有人坚持使用 Core Data;而如果要继续使用它,我们今天真正需要解决的问题又是什么。
为什么到了 2026 年,仍然还有人使用 Core Data
Core Data 自诞生至今已经 21 年了。在这期间,苹果的开发生态经历了数轮演进:从 Objective-C 到 Swift,从 UIKit 到 SwiftUI,从 GCD 到现代并发模型。即便在 SwiftData 推出数年之后,仍有不少开发者在继续使用 Core Data,而且使用它的存量项目依然非常庞大。
继续坚持使用 Core Data 的开发者,大致出于以下几种考量:
- 对 Core Data 足够熟悉,并不觉得它在今天已经“不可用”
- 相比看上去更现代的 SwiftData,更看重 Core Data 某些成熟而关键的能力
- 即便 GRDB / SQLiteData 提供了更强的性能或更直接的数据库控制力,仍然更喜欢 Core Data 的对象图设计思想和管理方式
- 旧项目仍在使用 Core Data,迁移到其他框架的成本过高
如果只是从“还能不能用”的角度说,Core Data 当然还能用,而且在不少项目里依然是务实的选择。
但问题在于,它越来越不像今天 Swift 项目里的东西了。
在现代 Swift / SwiftUI 工程中使用 Core Data,经常会有一种明显的错位感:它不是不能工作,而是它在代码层的表达方式、并发方式和工程协作方式,都越来越难与周围的现代代码风格自然地融合在一起。
所以,对仍在使用 Core Data 的人来说,真正的问题并不是“要不要立刻抛弃它”,而是:
如何让 Core Data 跟上项目其他部分已经发生的现代化演进。
Core Data 与现代 Swift 项目之间的错位
如果要寻找 Core Data 的进化方向,最好先明确它今天和现代 Swift 项目之间最主要的错位发生在哪里。
1. 模型代码的表现力已经落后于现代 Swift
和 SwiftData、SQLiteData 这类以代码为核心的声明方式不同,Core Data 的主流建模方式仍然是 Xcode 的模型编辑器。
但真正让 Core Data 与现代 Swift 项目脱节的,并不只是“模型放在编辑器里”这件事,而是它在 Swift 层面的模型代码表现力已经明显落后。
由于 Core Data 的底层历史来自 Objective-C,它在 Swift 世界中的默认模型声明方式始终带着很重的旧时代痕迹。很多在今天看起来理所当然的 Swift 语义,放到 NSManagedObject 上却并不能自然成立:
nil不总是能清晰对应到底层数据模型的nullDouble/Float这类值很难直接以符合直觉的 Optional 形式表达- 无法自然地把更丰富的 Swift 类型直接作为属性暴露出来
- 想改善这些问题时,往往不得不依赖手工桥接、计算属性和额外样板代码
这些做法当然能解决局部问题,但代价是模型声明层会迅速变得嘈杂。开发者为了获得更自然的 Swift 表达,不得不写出大量与业务无关的桥接代码,而这些代码反过来又削弱了 Core Data 最宝贵的一部分体验:对象图本该带来的清晰感和直接感。
换句话说,今天 Core Data 的问题并不是“不能建模”,而是它在 Swift 层的建模代码已经越来越难以自然地表达你的意图。
2. 并发体验仍然停留在 GCD 时代
Core Data 中的 NSManagedObject 不是线程安全的。随着项目变大,把所有 CRUD 都放在主线程上显然不是长久之计。
尽管从 Xcode 26 开始,NSManagedObjectContext 已经被标注为 Sendable 了,但这并没有改变 Core Data 实际的并发使用方式。为了保证线程安全,开发者依然需要通过 perform 去包装绝大多数操作。
这和今天 Swift 世界主流的并发表达方式之间有很明显的时代错位。
和 SwiftData 提供的 @ModelActor 相比,Core Data 的并发代码通常有几个问题:
- 很容易因为疏忽而写出线程不安全的代码
perform嵌套闭包的写法不直观,心智负担很重- 很难形成统一、清晰、可复用的隔离边界
- 这类负担还会进一步影响测试代码的质量,导致开发者更少去写系统性的并发测试
所以这里的问题也不是 Core Data “不能并发”,而是它的并发表达方式已经明显不适合今天的 Swift 开发习惯了。
3. 灵活性、类型安全与模型漂移之间的张力越来越大
Core Data 传统上在查询和排序上给了开发者很高的灵活性。
NSPredicate 和 NSSortDescriptor 都支持基于字符串的声明方式。这样的 API 很古老,但它也确实提供了很强的自由度。问题在于,这种自由度始终是以运行时风险为代价的:一旦字符串写错,就会造成运行时错误。
这也是 SwiftData、SQLiteData 这类新方案纷纷转向类型安全声明方式的主要原因。
但事情并没有那么简单。
类型安全当然能更早发现问题,但它往往也会压缩灵活调整的空间。对于很多已经上线、已经接入同步、或者底层模型已经不适合轻易变动的项目来说,属性名称、持久化字段名称、查询代码之间往往已经形成了很脆弱的平衡。一旦业务语言发生变化,开发者未必真的有空间去调整底层模型。
在这种情况下,开发者往往会选择在 Swift 层做一层映射,而不直接改动底层模型:
var title: String {
get {
guard let value = value(forKey: "name") as? String else {
preconditionFailure("Missing required value for `title` (name).")
}
return value
}
set {
setValue(newValue, forKey: "name")
}
}
这确实能让表现层的命名更贴近当前业务,但新的问题也随之出现了:
- Swift 属性名和持久化字段名脱节
- 基于字符串编写的谓词和排序代码更容易出错
- 手工映射层越来越厚,代码与底层模型发生漂移的概率越来越高
于是你会发现,问题已经不只是“字符串 API 不够安全”,而是:
一旦项目进入长期演进阶段,灵活性、类型安全和模型一致性之间会形成持续的张力。
真正棘手的,不只是 API 老,而是它越来越依赖经验与自觉
对于上面这些问题,我过去写过不少文章,也分享过不少在现代项目中继续使用 Core Data 的经验做法。但回头看,这些经验型解决方案有一个共同前提:开发者必须真正理解 Core Data 的底层行为,并且愿意持续遵守一套隐性的规范。
对于经验丰富的人类开发者来说,这件事或许还能做到。但在今天,这种前提已经越来越不牢靠了。
一方面,项目规模越来越大,团队协作越来越复杂,代码规范如果只是“约定俗成”,最终往往会逐渐失效。另一方面,AI 辅助编程正在快速进入日常开发流程,而大模型天然会优先输出它在预训练阶段见过的“常见写法”,而不是你项目内部那套需要长期维护的、细微但关键的规范。
这意味着,仅靠经验文章、团队自觉,甚至仅靠 Skill 去约束 AI 代码生成,已经很难真正解决问题了。
如果一套使用方式真的适合现代项目,它就不应该只是“资深开发者脑中的经验”,而应该尽可能体现在:
- 更清晰的 API 设计里
- 更稳定的源码表达层里
- 更可验证的工具链里
- 更容易被人和 AI 同时遵守的工作流里
换句话说,Core Data 今天真正缺的,也许不是更多技巧,而是一套能把这些技巧固化下来的表达方式和工程化支撑。
如果不打算替换 Core Data,我们还能做什么
到了这里,问题已经比较明确了。
如果你已经决定离开 Core Data,这篇文章对你意义不大——你完全可以转向 SwiftData、SQLiteData 或其他更符合当前偏好的方案。
但如果你仍然认可 Core Data 的对象图建模方式,仍然需要它成熟的迁移能力和历史兼容性,那么问题就不再是”要不要离开”,而是:有没有可能在不放弃 Core Data 的前提下,让它在现代 Swift 项目里重新站稳脚跟。
我过去一段时间一直在思考这个问题,最终把它落实进了一个开源库:CoreDataEvolution。
它不是一个取代 Core Data 的新框架,也不是要把开发者重新拉回旧技术。它做的事情更像是补缺:
- 用 Swift Macros 重塑模型声明层,让
NSManagedObject的表达更接近今天的 Swift 语义 - 引入 SwiftData 风格的 actor 隔离,让并发代码有清晰可验证的边界
- 提供映射层,在不轻易改动底层模型的前提下,同时改善排序、谓词等代码中的类型安全与命名表达
- 提供命令行工具,在源码声明和 Core Data 模型之间建立可持续的自动对齐机制
这些不是技巧的集合,而是一套试图把”经验”固化成工程结构的尝试。
下一篇文章里,我会展开聊具体的设计思路和实现方式。