SwiftUI获取Core Data数据的@FetchRequest
SwiftUI获取Core Data数据的@FetchRequest

SwiftUI获取Core Data数据的@FetchRequest

@FetchRequest 是 SwiftUI 提供的一个属性包装器(Property Wrapper),用于在 SwiftUI 视图中自动获取 Core Data 数据。

它会从 NSManagedObjectContext 中提取数据并监听数据变化。

如果数据发生变化,@FetchRequest 会自动更新 SwiftUI 视图。

基本语法

@FetchRequest(
    entity: [实体名称].entity(),
    sortDescriptors: [NSSortDescriptor(keyPath: \[实体名称]. [实体属性], ascending: true)]
)
var tasks: FetchedResults<[实体名称]>

例如,存在一个 .xcdatamodeld 文件中,有一个名为“Task”的实体,该实体包含name和timestamp两个属性。

@FetchRequest需要修改为:

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

代码解析

@FetchRequest(
    entity: Task.entity(),                        // 1. 实体 (Entity)
    sortDescriptors: [                           // 2. 排序描述符 (Sort Descriptors)
        NSSortDescriptor(keyPath: \Task.timestamp, ascending: true)
    ],
    predicate: NSPredicate(format: "name == %@", "John") // 3. 过滤条件 (Predicate) [可选]
)

1、entity

Task.entity() 指定获取的 Core Data 实体。

需要在 .xcdatamodeld 中定义 Task 实体。

2、sortDescriptors

使用 NSSortDescriptor 来对数据进行排序。

keyPath:指定要排序的属性。

ascending:true 表示升序,false 表示降序。

3、predicate(可选)

NSPredicate 用于过滤数据。

格式示例

NSPredicate(format: "name == %@", "John")

FetchedResults 的作用

@FetchRequest 返回的数据类型是 FetchedResults<Entity>。

FetchedResults 充当一个数组,可以使用 ForEach 遍历并在视图中显示数据。

示例

import SwiftUI
import CoreData

struct TaskListView: View {
    // 使用 @FetchRequest 获取 Task 数据
    @FetchRequest(
        entity: Task.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Task.timestamp, ascending: true)]
    )
    var tasks: FetchedResults<Task>

    var body: some View {
        List {
            ForEach(tasks, id: \.self) { task in
                Text("\(task.name ?? "No Name")")
            }
        }
    }
}

tasks 是 FetchedResults<Task> 类型,类似于一个数组,可以在 ForEach 中进行遍历。

每个 task 都是 Task 实体的一个实例,可以访问其属性(如 task.name)。

使用 @FetchRequest 时的注意事项

1、需要 managedObjectContext 注入

@FetchRequest 依赖于 Core Data 的 managedObjectContext。

在 App 主入口需要通过 .environment() 注入 viewContext:

@main
struct MyApp: App {
    let container = NSPersistentContainer(name: "YourProjectName")

    init() {
        container.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, container.viewContext)
        }
    }
}

2、监听数据变化

@FetchRequest 会自动监听 Core Data 数据的变化,当数据更新时,视图会自动重新渲染。

如果有对象被插入、更新或删除,@FetchRequest 会自动刷新视图。

3、复杂过滤时推荐使用 NSPredicate

predicate 可用于设置过滤条件,例如:

@FetchRequest(
    entity: Task.entity(),
    sortDescriptors: [NSSortDescriptor(keyPath: \Task.timestamp, ascending: true)],
    predicate: NSPredicate(format: "name CONTAINS[cd] %@", "Meeting")
)
var tasks: FetchedResults<Task>

更新 @FetchRequest 数据

1、创建一个新任务

func addTask(context: NSManagedObjectContext) {
    // 创建一个新的 Task 对象
    let newTask = Task(context: context)
    
    // 设置新任务的属性
    newTask.name = "New Task"         // 任务名称
    newTask.timestamp = Date()        // 记录创建时间
    
    // 尝试保存到 Core Data
    do {
        try context.save()            // 将更改提交到 Core Data
    } catch {
        // 如果发生错误,抛出异常并终止程序
        let nsError = error as NSError
        fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
    }
}

1、let newTask = Task(context: context)

通过 NSManagedObjectContext 创建一个 Task 实体实例。

context 是 Core Data 的 viewContext,负责管理数据的更改。

2、设置属性

newTask.name = “New Task”:新建任务的名称是 “New Task”。

newTask.timestamp = Date():将当前时间记录为 timestamp。

3、保存数据

try context.save():尝试将数据保存到 Core Data 持久化存储中。

如果 save() 失败,会触发 catch,然后使用 fatalError() 终止程序并抛出错误信息。

2、删除一个任务

func deleteTask(task: Task, context: NSManagedObjectContext) {
    // 从 Core Data 中删除 task 对象
    context.delete(task)

    // 尝试保存更改
    do {
        try context.save()            // 确保 Core Data 同步更新
    } catch {
        // 处理错误
        let nsError = error as NSError
        fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
    }
}

1、context.delete(task)

通过 context.delete() 方法删除 task 对象。

task 是一个已经存在的 Task 实体实例。

2、保存更改

try context.save():将删除操作提交到 Core Data。

如果 save() 失败,抛出错误并终止程序。

3、使用函数

添加任务

addTask(context: viewContext)

删除任务

if let taskToDelete = exchangeRates.first {
    deleteTask(task: taskToDelete, context: viewContext)
}

4、注意

context.save() 必须在对数据进行更改(新增、删除、修改)后调用,否则更改不会被保存。

如果 save() 失败,fatalError() 会导致应用崩溃。在生产环境中,应该使用更安全的错误处理机制,比如:

总结

@FetchRequest 是 SwiftUI 中获取 Core Data 数据的便捷工具。

它会监听数据变化,并在 Core Data 更新时自动重新渲染视图。

通过 sortDescriptors 和 predicate 可以灵活排序和过滤数据。

@FetchRequest 需要 managedObjectContext 注入,否则无法正常工作。

如果Core Data在Xcode中预览报错,请参考《Core Data预览报错问题

相关文章

Core Data预览报错问题:https://fangjunyu.com/2025/03/30/core-data%e9%a2%84%e8%a7%88%e6%8a%a5%e9%94%99%e9%97%ae%e9%a2%98/

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

发表回复

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