Core Data管理数据生命周期的NSManagedObjectContext
Core Data管理数据生命周期的NSManagedObjectContext

Core Data管理数据生命周期的NSManagedObjectContext

NSManagedObjectContext(简称 context)是 Core Data 的核心对象之一,负责管理应用中的数据生命周期,包括:

创建:向 Core Data 中添加新数据。

读取:从持久化存储中获取数据。

更新:修改数据并保存更改。

删除:删除数据并提交更改。

这里涉及的部分代码和知识,需要查看@FetchRequest的文章《SwiftUI获取Core Data数据的@FetchRequest》。

核心概念

context 是 Core Data 中的临时工作区,类似于一个缓冲区。

对数据的任何更改都会在 context 中暂存,直到调用 save() 才会同步到持久化存储(通常是 SQLite 数据库)。

如果没有显式调用 save(),数据更改不会持久化。

常见场景

1、添加数据

func addTask(context: NSManagedObjectContext) {
    let newTask = Task(context: context)
    newTask.name = "Learn Core Data"
    newTask.timestamp = Date()
    
    do {
        try context.save()  // 保存更改到数据库
    } catch {
        print("Error saving task: \(error.localizedDescription)")
    }
}

2、读取数据

使用 @FetchRequest 或 NSFetchRequest 从 context 获取数据。

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Task.timestamp, ascending: true)],
    animation: .default)
private var tasks: FetchedResults<Task>

3、更新数据

func updateTask(task: Task, context: NSManagedObjectContext) {
    task.name = "Updated Task Name"
    
    do {
        try context.save()  // 保存更新
    } catch {
        print("Error updating task: \(error.localizedDescription)")
    }
}

4、删除数据

func deleteTask(task: Task, context: NSManagedObjectContext) {
    context.delete(task)

    do {
        try context.save()  // 删除后保存
    } catch {
        print("Error deleting task: \(error.localizedDescription)")
    }
}

如何创建 NSManagedObjectContext?

1、使用 NSPersistentContainer 获取 viewContext

let container = NSPersistentContainer(name: "MyDataModel")
container.loadPersistentStores { (storeDescription, error) in
    if let error = error {
        fatalError("Error loading Core Data: \(error)")
    }
}

// 获取 `viewContext`
let context = container.viewContext

2、通过 @Environment 传递到视图

@Environment(\.managedObjectContext) private var viewContext

viewContext 和 backgroundContext 的区别

viewContext

主要在主线程中运行。

适用于 UI 相关的操作(如 @FetchRequest)。

backgroundContext

在后台线程中运行,避免阻塞主线程。

适合大批量数据导入或异步操作。

let backgroundContext = container.newBackgroundContext()
backgroundContext.perform {
    let task = Task(context: backgroundContext)
    task.name = "Background Task"
    
    do {
        try backgroundContext.save()
    } catch {
        print("Error saving in background: \(error.localizedDescription)")
    }
}

常见方法

1、fetch查询数据库

执行一个 NSFetchRequest 查询数据库,返回对象类型为[NSManagedObject]。

let request = NSFetchRequest<UserForeignCurrency>(entityName: "UserForeignCurrency")
let results = try viewContext.fetch(request)

2、count统计

获取符合查询条件的记录数,返回对象类型为Int。

let request = NSFetchRequest<UserForeignCurrency>(entityName: "UserForeignCurrency")
let count = try viewContext.count(for: request)

3、object对象

通过对象 ID 获取对象,可能尚未加载其属性,返回对象类型为NSManagedObject。

let objectID = someCurrency.objectID
let object = viewContext.object(with: objectID)

4、existingObject对象

和 object(with:) 类似,但如果对象不存在会抛出异常,返回对象类型为NSManagedObject。

let object = try viewContext.existingObject(with: objectID)

5、insert插入对象

通常不直接用,Swift 用法是通过构造函数:

let newCurrency = UserForeignCurrency(context: viewContext)
newCurrency.symbol = "USD"
newCurrency.amount = 123.45

6、delete删除对象

删除某个托管对象。

viewContext.delete(someCurrency)

7、refresh刷新对象状态

刷新对象状态(从数据库重新加载,或者重置为未加载状态)。

viewContext.refresh(someCurrency, mergeChanges: true)

8、rollback回滚

撤销所有未保存的更改。

viewContext.rollback()

9、reset清空

彻底清空上下文(所有未保存对象都会丢失)。

viewContext.reset()

10、save保存

将所有更改保存到数据库。

if viewContext.hasChanges {
    try viewContext.save()
}

11、hasChanges是否修改

判断是否有未保存更改。

if viewContext.hasChanges {
    // 可以保存
}

12、perform异步执行

在上下文线程异步执行任务。

viewContext.perform {
    // 后台安全执行
}

13、performAndWait同步执行

在上下文线程同步执行任务(阻塞当前线程)。

viewContext.performAndWait {
    // 同步任务
}

14、mergeChanges合并变更

将另一个上下文的更改合并到当前上下文。

NotificationCenter.default.addObserver(forName: .NSManagedObjectContextDidSave, object: nil, queue: nil) { notification in
    viewContext.mergeChanges(fromContextDidSave: notification)
}

15、undoManager撤销管理器

设置或使用撤销管理器。

viewContext.undoManager?.undo()
viewContext.undoManager?.redo()

16、undo/redo/resetUndoManager

手动撤销、重做或undo管理。

17、parent父上下文

当前上下文的父上下文,支持“分层结构”操作。

使用示例

在使用viewContext中,可以搭配NSFetchRequest使用,例如快速查询最新的日期:

func fetchLatestDate() -> Date? {
    let request = NSFetchRequest<NSDictionary>(entityName: "Eurofxrefhist")
    request.resultType = .dictionaryResultType
    request.propertiesToFetch = ["date"]
    request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
    request.fetchLimit = 1

    do {
        if let result = try viewContext.fetch(request).first,
           let latestDate = result["date"] as? Date {
            return latestDate
        }
    } catch {
        print("Error fetching latest date: \(error)")
    }
    return nil
}

在这段代码中,通过NSFetchRequest<NSDictionary>快速查询最新日期的数据。

通过viewContext.fetch()获取最新数据数组的第一个元素,并解包日期字段获取最新的日期。

最后,Xcode输出的内容为:

Optional(2025-04-10 16:00:00 +0000)

总结

NSManagedObjectContext 负责管理 Core Data 的数据生命周期。

通过 viewContext 处理 UI 数据,通过 backgroundContext 进行后台操作。

确保在数据更改后调用 context.save() 来持久化数据。

相关文章

1、SwiftUI获取Core Data数据的@FetchRequest:https://fangjunyu.com/2025/03/30/swiftui%e8%8e%b7%e5%8f%96core-data%e6%95%b0%e6%8d%ae%e7%9a%84fetchrequest/

2、Core Data管理数据模型的NSPersistentContainer:https://fangjunyu.com/2025/03/29/core-data%e7%ae%a1%e7%90%86%e6%95%b0%e6%8d%ae%e6%a8%a1%e5%9e%8b%e7%9a%84nspersistentcontainer/

3、Core Data NSManagedObjectContext的后台上下文backgroundContext:https://fangjunyu.com/2025/03/31/core-data-nsmanagedobjectcontext%e7%9a%84%e5%90%8e%e5%8f%b0%e4%b8%8a%e4%b8%8b%e6%96%87backgroundcontext/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注