本篇目标
理解 Core Data 的基本概念,掌握数据模型、实体、上下文、增删改查操作,能用 Core Data 完成一个简单的数据存储模块。
一、Core Data 是什么
Core Data 是 Apple 提供的对象图管理与持久化框架,用于管理应用中的模型数据。
核心特点:
面向对象,直接操作 Swift 对象
支持复杂数据模型与关系
提供数据校验、版本迁移
与 SwiftUI 深度集成
底层可基于 SQLite 存储
适合场景:
需要结构化存储的数据
数据量大、需要查询和排序
对象之间有复杂关系
需要版本迁移
不适合场景:
简单键值(用 UserDefaults)
少量文件(用文件读写)
敏感信息(用 Keychain)
二、核心概念
主要组件:
组件 | 作用 |
|---|---|
NSManagedObjectModel | 数据模型(实体定义) |
NSPersistentStoreCoordinator | 持久化协调器 |
NSManagedObjectContext | 上下文,操作数据 |
NSPersistentContainer | 容器,封装以上组件 |
NSManagedObject | 数据对象(实体实例) |
关系图:
PersistentContainer
├── ManagedObjectModel(数据模型)
├── PersistentStoreCoordinator(存储协调)
└── ViewContext(主上下文)
└── ManagedObject(数据对象)说明:
数据模型定义实体和属性。
上下文是操作数据的入口。
容器封装了以上组件,简化初始化。
三、创建数据模型

步骤:
在 Xcode 中 File → New → File from Template
选择 Data Model
命名,如
Model.xcdatamodeld点击 Add Entity 添加实体
添加属性和类型
示例实体:
实体名:Note
属性 | 类型 | 说明 |
|---|---|---|
id | UUID | 唯一标识 |
title | String | 标题 |
content | String | 内容 |
createdAt | Date | 创建时间 |
实体选项:
Codegen 选择
Class Definition(自动生成类)或
Manual/None(手动创建类)
推荐:初学选 Class Definition,Xcode 自动生成。
四、初始化 PersistentContainer
在 App 中初始化:
import SwiftUI
import CoreData
@main
struct MyApp: App {
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "Model")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("加载失败:\(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, container.viewContext)
}
}
}说明:
name与数据模型文件名一致。loadPersistentStores加载存储。viewContext是主线程上下文。通过
environment注入到视图。
SwiftUI 中使用:
struct ContentView: View {
@Environment(\.managedObjectContext) private var context
var body: some View {
Text("内容")
}
}五、创建数据
使用 NSEntityDescription:
let note = Note(context: context)
note.id = UUID()
note.title = "第一条笔记"
note.content = "这是内容"
note.createdAt = Date()
do {
try context.save()
print("保存成功")
} catch {
print("保存失败:\(error)")
}说明:
Note(context:)是自动生成的初始化器。修改属性后需要调用
save()。上下文会自动跟踪对象变化。
批量创建:
for i in 1...5 {
let note = Note(context: context)
note.id = UUID()
note.title = "笔记 \(i)"
note.content = "内容 \(i)"
note.createdAt = Date()
}
try? context.save()六、查询数据
使用 @FetchRequest(SwiftUI 推荐):
struct NoteListView: View {
@Environment(\.managedObjectContext) private var context
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Note.createdAt, ascending: false)],
animation: .default
)
private var notes: FetchedResults<Note>
var body: some View {
List {
ForEach(notes) { note in
VStack(alignment: .leading) {
Text(note.title ?? "")
.font(.headline)
Text(note.content ?? "")
.font(.subheadline)
.foregroundColor(.gray)
}
}
}
}
}使用 NSFetchRequest(代码中):
let request: NSFetchRequest<Note> = Note.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Note.createdAt, ascending: false)]
request.fetchLimit = 10
do {
let notes = try context.fetch(request)
print("共 \(notes.count) 条")
} catch {
print("查询失败:\(error)")
}带条件查询:
let request: NSFetchRequest<Note> = Note.fetchRequest()
request.predicate = NSPredicate(format: "title CONTAINS %@", "iOS")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Note.createdAt, ascending: false)]
let results = try? context.fetch(request)常用 NSPredicate:
格式 | 说明 |
|---|---|
| 等于 |
| 包含 |
| 大于 |
| 前缀 |
| 后缀 |
| 范围 |
七、更新数据
直接修改属性:
let request: NSFetchRequest<Note> = Note.fetchRequest()
if let note = try? context.fetch(request).first {
note.title = "新标题"
try? context.save()
}说明:
Core Data 对象是引用类型。
修改属性后,调用
save()持久化。未保存的修改在上下文中存在,但不写入磁盘。
八、删除数据
删除单条:
context.delete(note)
try? context.save()在列表中删除:
ForEach(notes) { note in
Text(note.title ?? "")
}
.onDelete { indexSet in
indexSet.forEach { index in
let note = notes[index]
context.delete(note)
}
try? context.save()
}批量删除:
let request: NSFetchRequest<NSFetchRequestResult> = Note.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print("批量删除失败:\(error)")
}九、排序与分页
排序:
request.sortDescriptors = [
NSSortDescriptor(keyPath: \Note.createdAt, ascending: false),
NSSortDescriptor(keyPath: \Note.title, ascending: true)
]分页:
request.fetchOffset = 0
request.fetchLimit = 20说明:
fetchOffset:跳过的记录数。fetchLimit:返回的最大记录数。用于列表分页加载。
十、数据模型关系
一对多关系:
例如:分类(Category)与笔记(Note)。
Category 有
notes(to-many)Note 有
category(to-one)
定义:
在 Category 实体中添加
notes,类型为 To Many。在 Note 实体中添加
category,类型为 To One。设置反向关系。
使用:
let category = Category(context: context)
category.name = "工作"
let note = Note(context: context)
note.title = "会议记录"
note.category = category
try? context.save()查询某分类下的笔记:
let request: NSFetchRequest<Note> = Note.fetchRequest()
request.predicate = NSPredicate(format: "category.name == %@", "工作")
let notes = try? context.fetch(request)十一、数据校验
在数据模型中,可以为属性设置校验规则:
最小长度
最大长度
最小值
最大值
是否可选
保存前校验:
do {
try context.save()
} catch let error as NSError {
print("校验失败:\(error.userInfo)")
}手动校验:
if note.title?.isEmpty == true {
print("标题不能为空")
}十二、封装 Core Data 操作
class NoteRepository {
private let context: NSManagedObjectContext
init(context: NSManagedObjectContext) {
self.context = context
}
func create(title: String, content: String) -> Note {
let note = Note(context: context)
note.id = UUID()
note.title = title
note.content = content
note.createdAt = Date()
return note
}
func fetchAll() -> [Note] {
let request: NSFetchRequest<Note> = Note.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Note.createdAt, ascending: false)]
return (try? context.fetch(request)) ?? []
}
func update(_ note: Note, title: String) {
note.title = title
}
func delete(_ note: Note) {
context.delete(note)
}
func save() {
if context.hasChanges {
try? context.save()
}
}
}使用:
let repo = NoteRepository(context: context)
let note = repo.create(title: "标题", content: "内容")
repo.save()十三、避坑指南
不要在错误线程操作上下文:viewContext 是主线程。
修改后要 save:否则不会持久化。
@FetchRequest 自动刷新:数据变化时界面自动更新。
批量删除要合并上下文:否则 @FetchRequest 不会刷新。
实体属性可选性:String 属性建议用可选类型或提供默认值。
数据迁移:模型变化时要配置迁移策略。
不要存大文件:图片、音频用文件系统。
十四、检查清单
[ ] 理解 Core Data 的核心概念
[ ] 能创建数据模型和实体
[ ] 会初始化 PersistentContainer
[ ] 能创建、查询、更新、删除数据
[ ] 会使用 @FetchRequest
[ ] 会使用 NSPredicate 条件查询
[ ] 理解数据模型关系
[ ] 能封装 Core Data 操作
[ ] 了解数据迁移