在视图层次结构中传递CoreData关系

时间:2020-04-14 20:20:28

标签: swift core-data swiftui

我非常努力地将具有牢固一对二关系的CoreData对象传递到我的视图层次结构中。

想象一个Todolist应用程序:

  1. 每个列表对象与一个Task对象都有一个一对多的关系。

  2. 每个任务对象与一个子任务对象都有一个一对多的关系。

我用FetchedRequests在根处查询CoreData以获得List对象。现在,我遍历Task对象,并为每个对象创建一个View。然后,在每个视图中,我都需要遍历其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进行查询吗?我真的不知道为什么要将我已经使用绑定和根级数据结构的内容迁移到coredata如此困难。

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

这是我制作的一个示例项目,目的是简化问题。我想知道是否有人可以看看?

https://github.com/ryanpeach/MySwiftTaskList

这些是主要视图:

TaskList +扩展程序

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
    }
}

ContentView(根)

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)
        }
    }
}

TaskListView

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)的示例,它运行得很完美,所以我想我只是不了解这种数据类型的限制。

1 个答案:

答案 0 :(得分:0)

Discord上的一位用户向我提到,对于CoreData对象,我应该使用@ObservedObject而不是@Binding,它的使用效果很好。真的就是这么简单。