CoreData และ SwiftUI: บริบทในสภาพแวดล้อมไม่ได้เชื่อมต่อกับผู้ประสานงานร้านค้าแบบถาวร


10

ฉันกำลังพยายามสอนตัวเองข้อมูลหลักโดยการสร้างแอปจัดการการบ้าน รหัสของฉันสร้างได้ดีและแอพทำงานได้ดีจนกระทั่งฉันพยายามเพิ่มการบ้านใหม่ในรายการ ฉันได้รับข้อผิดพลาดนี้Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c25719e8)ในบรรทัดต่อไปนี้: ForEach(courses, id: \.self) { course in. Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2823cb3a0>คอนโซลนอกจากนี้ยังมีข้อผิดพลาดนี้:

ฉันรู้น้อยมากเกี่ยวกับคอร์ข้อมูลและฉันกำลังสูญเสียเป็นสิ่งที่อาจเป็นปัญหา ฉันได้ตั้งค่าเอนทิตี "การมอบหมาย" และ "หลักสูตร" ในรูปแบบข้อมูลโดยที่หลักสูตรมีความสัมพันธ์แบบหนึ่งต่อหลายคนกับการมอบหมาย การมอบหมายแต่ละครั้งจะถูกจัดหมวดหมู่ภายใต้หลักสูตรเฉพาะ

นี่คือรหัสสำหรับมุมมองที่เพิ่มการมอบหมายใหม่ให้กับรายการ:

    struct NewAssignmentView: View {

    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Course.entity(), sortDescriptors: []) var courses: FetchedResults<Course>

    @State var name = ""
    @State var hasDueDate = false
    @State var dueDate = Date()
    @State var course = Course()

    var body: some View {
        NavigationView {
            Form {
                TextField("Assignment Name", text: $name)
                Section {
                    Picker("Course", selection: $course) {
                        ForEach(courses, id: \.self) { course in
                            Text("\(course.name ?? "")").foregroundColor(course.color)
                        }
                    }
                }
                Section {
                    Toggle(isOn: $hasDueDate.animation()) {
                        Text("Due Date")
                    }
                    if hasDueDate {
                        DatePicker(selection: $dueDate, displayedComponents: .date, label: { Text("Set Date:") })
                    }
                }
            }
            .navigationBarTitle("New Assignment", displayMode: .inline)
            .navigationBarItems(leading: Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }, label: { Text("Cancel") }),
                                trailing: Button(action: {
                                    let newAssignment = Assignment(context: self.moc)
                                    newAssignment.name = self.name
                                    newAssignment.hasDueDate = self.hasDueDate
                                    newAssignment.dueDate = self.dueDate
                                    newAssignment.statusString = Status.incomplete.rawValue
                                    newAssignment.course = self.course
                                    self.presentationMode.wrappedValue.dismiss()
                                }, label: { Text("Add").bold() }))
        }
    }
}

แก้ไข: นี่คือรหัสใน AppDelegate ที่ตั้งค่าคอนเทนเนอร์ถาวร:

lazy var persistentContainer: NSPersistentCloudKitContainer = {
    let container = NSPersistentCloudKitContainer(name: "test")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

และรหัสใน SceneDelegate ที่ตั้งค่าสภาพแวดล้อม:

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

    // Get the managed object context from the shared persistent container.
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
    // Add `@Environment(\.managedObjectContext)` in the views that will need the context.
    let contentView = ContentView().environment(\.managedObjectContext, context)

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView)
        self.window = window
        window.makeKeyAndVisible()
    }
}

คุณเพิ่มบริบทวัตถุที่ได้รับการจัดการให้กับสภาพแวดล้อมที่ไหน บริบทวัตถุที่ได้รับการจัดการสร้างขึ้นอย่างไร ดูเหมือนว่าคุณยังไม่ได้เชื่อมต่อกับผู้ประสานงานร้านค้าถาวร
Paulw11 11

ฉันเพิ่มรหัสที่ฉันเพิ่มกระทรวงพาณิชย์ให้กับสภาพแวดล้อมในโพสต์ต้นฉบับของฉันสำหรับคุณ
Kevin Olmats

@KevinOlmats คำตอบของฉันช่วยได้ไหม?
fulvio

ตรวจสอบว่าคุณได้กำหนดบริบทผ่านทางสิ่งแวดล้อม.environment(\.managedObjectContext, viewContext)
onmyway133

@ onmyway133 นี่เป็นคำตอบที่ถูกต้อง
Kevin Olmats

คำตอบ:


8

คุณไม่ได้บันทึกบริบทจริงๆ คุณควรดำเนินการดังต่อไปนี้:

let newAssignment = Assignment(context: self.moc)
newAssignment.name = self.name
newAssignment.hasDueDate = self.hasDueDate
newAssignment.dueDate = self.dueDate
newAssignment.statusString = Status.incomplete.rawValue
newAssignment.course = self.course

do {
    try self.moc.save()
} catch {
    print(error)
}

นอกจากนี้คุณ@FetchRequest(...)อาจมีลักษณะเช่นนี้:

@FetchRequest(fetchRequest: CourseItem.getCourseItems()) var courses: FetchedResults<CourseItem>

คุณสามารถแก้ไขCourseItemชั้นเรียนของคุณเพื่อจัดการsortDescriptorsสิ่งต่อไปนี้:

public class CourseItem: NSManagedObject, Identifiable {
    @NSManaged public var name: String?
    @NSManaged public var dueDate: Date?
    // ...etc
}

extension CourseItem {
    static func getCourseItems() -> NSFetchRequest<CourseItem> {
        let request: NSFetchRequest<CourseItem> = CourseItem.fetchRequest() as! NSFetchRequest<CourseItem>

        let sortDescriptor = NSSortDescriptor(key: "dueDate", ascending: true)

        request.sortDescriptors = [sortDescriptor]

        return request
    }
}

จากนั้นคุณจะปรับเปลี่ยนForEach(...)สิ่งต่อไปนี้และยังสามารถจัดการการลบรายการได้อย่างง่ายดายเช่นกัน:

ForEach(self.courses) { course in
    // ...
}.onDelete { indexSet in
    let deleteItem = self.courses[indexSet.first!]
    self.moc.delete(deleteItem)

    do {
        try self.moc.save()
    } catch {
        print(error)
    }
}

สิ่งหนึ่งที่คุณต้องการมั่นใจคือ "ชื่อชั้น" ถูกตั้งค่าเป็น "CourseItem" ซึ่งตรงกับCourseItemชั้นเรียนที่เราสร้างไว้ก่อนหน้านี้

เพียงคลิกENTITIESใน.xcdatamodeIdไฟล์ของคุณและตั้งค่าทุกอย่างเป็นดังต่อไปนี้ (รวมถึงโมดูลเป็น "โมดูลผลิตภัณฑ์ปัจจุบัน" และCodegenเป็น "คู่มือ / ไม่มี"):

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.