【问题标题】:Passing CoreData relationships down a view hierarchy将 CoreData 关系向下传递到视图层次结构
【发布时间】:2020-07-27 16:48:27
【问题描述】:

我正在努力将具有强 one2many 关系的 CoreData 对象传递到我的视图层次结构中。

想象一下 Todolist 应用:

  1. 每个 List 对象都与 Task 对象存在一对多关系。

  2. 每个 Task 对象都与 SubTask 对象存在一对多关系。

我使用 FetchedRequests 在根处查询 CoreData 以获取 List 对象。我现在遍历任务对象,并为每个对象创建一个视图。然后在每个视图中,我需要遍历它的 SubTask 对象。在这些级别中的每一个,都可以进行编辑,并且应该进行备份。

我很难处理这样的代码:

struct TaskListView: View {
    @Environment(\.managedObjectContext) var managedObjectContext

    @Binding var taskData: TaskData

    var body: some View {
        List{
            ForEach(self.taskList.tasks ?? [], id: \.id) { t in
                TaskRowView(taskData: $t)
            }
        }
    }
}

这会产生很多错误。喜欢:

  1. 如果我将其更改为使用索引,它会显示没有属性 .indicies

  2. 现在它说通用结构“ForEach”要求“NSOrderedSet”符合“RandomAccessCollection”

  3. “NSOrderedSet.Element”(又名“Any”)类型的值没有成员“id”

还有很多其他的。

你有更好的方法吗?我应该在每一步都从 coredata 进行查询吗?我真的不知道为什么将我已经使用的 Bindings 和根级数据结构迁移到 coredata 如此困难。

我似乎无法通过 UUID 从数据库中仅查询一项。我希望这更像是 mongodb 而不是 sql。

这是我为简化问题而制作的示例项目。不知道有没有人可以看看?

https://github.com/ryanpeach/MySwiftTaskList

这些是主要视图:

任务列表+扩展

extension TaskList: Identifiable {

    var duration: Double {
        var out = 0.0
        for t in self.tasks ?? [] {
            out += (t as! Task).duration
        }
        return out
    }

    func getTasks() -> [Task] {
        var out: [Task] = []
        for t in self.tasks ?? [] {
            out.append(t as! Task)
        }
        return out
    }
}

内容视图(根)

import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(
        entity: TaskList.entity(),
        sortDescriptors: [
            NSSortDescriptor(
                keyPath: \TaskList.name,
                ascending: true
            )
    ]) var taskListList: FetchedResults<TaskList>

    @State private var taskListName: String = ""

    var body: some View {
        NavigationView {
            VStack {
                HStack{
                    TextField("TaskList Name", text: $taskListName)
                    Button(action: {
                        self.addTaskList()
                    }){
                        Text("Create Task List")
                    }
                }
                List{
                    ForEach(self.taskListList, id: \.name) { tl in
                        NavigationLink(destination: TaskListView(taskList: tl)) {
                            Text(tl.name)
                            Text(String(tl.duration))
                        }
                    }
                }
            }
        }
    }

    func addTaskList() {
        let newTask = TaskList(context: managedObjectContext)
        // newTask.id = UUID()
        newTask.name = taskListName

        do {
            try managedObjectContext.save()
        } catch {
            print(error)
        }
    }
}

任务列表视图

import SwiftUI
import CoreData

struct TaskListView: View {
    @Environment(\.managedObjectContext) var managedObjectContext
    @State private var taskName: String = ""

    /* Option1: Does not work
    var fetchRequest: FetchRequest<Task>
    var tasks: FetchedResults<Task>

    @State private var _taskList: TaskList?

    init(taskList: TaskList) {
        fetchRequest = FetchRequest<Task>(
            entity: Task.entity(),
            sortDescriptors: [
                NSSortDescriptor(
                    keyPath: \Task.order,
                    ascending: true
                )
            ],
            predicate: NSPredicate(format: "taskList = %@", taskList)
        )
        _taskList = taskList
        tasks = fetchRequest.wrappedValue
    }
    */

    @Binding var taskList: TaskList

    var body: some View {
        VStack {
            HStack{
                TextField("Task Name", text: $taskName)
                Button(action: {
                    self.addTask()
                }){
                    Text("Create Task")
                }
            }
            List{
                ForEach(self.taskList.getTasks(), id: \.order) { <------- The errors happen here
                    t in
                    HStack{
                        Text(t.name)
                        Text(String(t.duration))
                    }
                }
            }
        }
    }

    func addTask() {
        let newTask = Task(context: managedObjectContext)
        // newTask.id = UUID()
        newTask.name = taskName
        taskList.addToTasks(newTask)

        do {
            try managedObjectContext.save()
        } catch {
            print(error)
        }
    }
}

struct TaskListView_Previewer: View {
    @State var taskList: TaskList
    var body: some View {
        TaskListView(
            taskList: $taskList
        )
    }
}

我真的很感激能从这一切中获得学习经验。只是不太确定我“应该”如何使用 CoreData 处理我的数据。我有一些从类似于 json 的静态数据源工作的示例,并且它完美地工作,所以我想我只是不了解这种数据类型的限制。

【问题讨论】:

    标签: swift core-data swiftui


    【解决方案1】:

    Discord 上的一个用户向我提到我应该使用 @ObservedObject 而不是 @Binding 来处理 CoreData 对象,它的效果非常好。就这么简单。

    【讨论】:

      猜你喜欢
      • 2023-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多