在 CoreData 中保存项目启动导航

时间:2021-05-10 08:34:44

标签: core-data swiftui swiftui-navigationlink

在我的 ContentView 中,我有一个 FetchRequest<Project>。我使用 ProjectView 导航到 NavigationLink。我从 ProjectView 使用另一个 AddItemView 导航到 NavigationLink。在 AddItemView 中,当我将 Item 添加到 Project 并调用 container.viewContext.save() 时,AddItemView 会自动关闭回 ContentView。 我的猜测是保存到 CoreData 会更新 FetchRequest<Project> 列表,从而更新视图,但我不确定。

如何将新的 Item 保存到 Project 中的 CoreData 并且只导航回 ProjectView 而不是 ContentView

重现:

  1. 在 CloudKit 中创建新的单一视图应用程序并检查核心数据和主机
  2. 在 .xcdatamodel 中删除默认实体并将其替换为名为 Project 的实体,该实体具有属性 date: Date 和 title: String 以及名为 Item 的实体,其具有属性名称:String。给项目一个名为 items 的关系(键入 Item)并在右侧选择“to many”。给项目一个称为项目的关系,它是项目的逆。
  3. 将 Persistence.swift 中的代码替换为:
// Persistence.swift
import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    let container: NSPersistentCloudKitContainer

    init(inMemory: Bool = false) {
        container = NSPersistentCloudKitContainer(name: "CoreDataBug")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                Typical reasons for an error here include:
                * The parent directory does not exist, cannot be created, or disallows writing.
                * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                * The device is out of space.
                * The store could not be migrated to the current model version.
                Check the error message to determine what the actual problem was.
                */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
    }
}
  1. 复制内容视图
//  ContentView.swift

import SwiftUI

struct ContentView: View {

    @Environment(\.managedObjectContext) var moc

    let projects: FetchRequest<Project>

    init() {
        projects = FetchRequest<Project>(entity: Project.entity(), sortDescriptors: [
            NSSortDescriptor(keyPath: \Project.date, ascending: false)
        ])
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(projects.wrappedValue) { project in
                    NavigationLink(destination: ProjectView(project: project)) {
                        Text(project.title ?? "Title")
                    }
                }
            }
            .navigationTitle("Projects")
            .toolbar {
                ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) {
                    Button {
                        withAnimation {
                            let project = Project(context: moc)
                            let now = Date()
                            project.date = now
                            project.title = now.description
                            try? moc.save()
                        }
                    } label: {
                        Label("Add Project", systemImage: "plus")
                    }
                }
            }
        }
    }
}
  1. 创建 ProjectView.swift 并复制:
// ProjectView.swift
import SwiftUI

struct ProjectView: View {

    @ObservedObject var project: Project

    var items: [Item] {
        project.items?.allObjects as? [Item] ?? []
    }

    var body: some View {
        List {
            ForEach(items) { item in
                Text(item.name ?? "")
            }
        }
        .toolbar {
            ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) {
                NavigationLink(destination: AddItemView(project: project)) {
                    Label("Add Item", systemImage: "plus")
                }
            }
        }
    }
}
  1. 创建 AddItemView.swift 并复制:
import SwiftUI

// AddItemView.swift

import SwiftUI

struct AddItemView: View {

    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedObjectContext) var moc

    let project: Project

    @State private var selectedName: String =  ""

    var body: some View {
        TextField("Type name here", text: $selectedName)
            .navigationTitle("Add Item")
            .navigationBarItems(trailing: Button("Add") {
                let ingestion = Item(context: moc)
                ingestion.project = project
                ingestion.name = selectedName
                try? moc.save()
                presentationMode.wrappedValue.dismiss()
            })
    }
}
  1. 运行应用。点击右上角的加号。单击刚刚滑入的项目。在 ProjectView 中再次单击右上角的加号。在 TextField 中输入名称,然后单击右上角的添加。当 AddItemView 被解除时,它可能会回到 ContentView。如果没有,请向项目添加另一个项目。

0 个答案:

没有答案