Core Data 是什么、适合什么

Core Data 不是简单的"SQLite 封装",它是一个对象图管理框架:你操作的是 Swift 对象,Core Data 负责在合适的时机把它们写进磁盘,并维护对象之间的关系、校验与懒加载。对需要结构化记录、有对象关系、要查询排序的本地数据,Core Data 是苹果生态的默认选择。

判断用不用 Core Data:只有几个开关状态,用 UserDefaults 就够;一旦数据成"表"、要查要排序要有关系,就上 Core Data。

它的学习曲线偏陡,概念多,但把核心几个对象弄清楚后,日常增删改查其实很直观。

持久化容器与托管上下文

整个栈的入口是 NSPersistentContainer,它负责加载持久化存储并提供一个托管上下文(managedObjectContext)。你在上下文里增删改对象,调用 save() 时才真正写盘。

let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores { desc, error in
    if let error = error {
        fatalError("加载持久化存储失败:\(error)")
    }
}
let context = container.viewContext   // 主线程上下文,供 UI 使用
几个核心角色
  • NSPersistentContainer容器,加载存储、提供上下文。
  • NSManagedObjectContext上下文,对象的工作区,改动在这里发生。
  • NSManagedObject托管对象,对应数据表里的一行。
  • save()把上下文中的改动提交到磁盘。

建模:实体与关系

在 Xcode 的 Data Model 编辑器里画实体:新建一个 Entity,给它加属性(字符串、日期、数值),再设定主字段。编译后 Core Data 会生成对应的 NSManagedObject 子类。

实体之间还能建关系:一对多、多对多。比如一个 Folder 有很多 Note,这种关系在 Core Data 里是真正的对象引用,取 folder.notes 就是它下面的所有笔记,不用自己写 join 查询。

Core Data 持久化示意:中央打开的抽象立方体数据仓库内部由节点与连线构成对象关系网络,周围散落小型存储方块与磁盘剪影
对象图:实体之间是真实引用关系,你操作的是对象,落盘由 Core Data 代劳。

增删改查与 FetchRequest

查询用 NSFetchRequest:指定实体、排序、谓词(过滤条件),然后让上下文执行。新增就是在上下文里 insert 一个新对象,赋值后 save。

// 查询:按更新时间倒序取笔记
let req: NSFetchRequest<Note> = Note.fetchRequest()
req.sortDescriptors = [NSSortDescriptor(key: "updatedAt", ascending: false)]
let notes = try? context.fetch(req)

// 新增
let note = Note(context: context)
note.title = "新笔记"
note.createdAt = Date()
try? context.save()

谓词 NSPredicate 用来做条件过滤,例如"只查未完成的"。复杂查询记得加索引,并控制一次 fetch 的条数,别把几万条对象全拉进内存。

与 SwiftUI 结合

SwiftUI 用 @FetchRequest 把查询直接接到视图上:数据一变,列表自动刷新。容器通过 environment 注入,整个 app 共享同一份存储。

struct NoteList: View {
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Note.updatedAt, ascending: false)]
    ) var notes: FetchedResults<Note>

    var body: some View {
        List(notes) { note in
            Text(note.title ?? "未命名")
        }
    }
}

这就是 Core Data 在 SwiftUI 里最舒服的姿势:声明一个 FetchRequest,剩下的增删改触发保存后,列表自动更新,不用手动刷新。