CoreData và SwiftUI: Bối cảnh trong môi trường không được kết nối với một điều phối viên cửa hàng liên tục


10

Tôi đang cố gắng dạy cho mình Dữ liệu cốt lõi bằng cách xây dựng một ứng dụng quản lý bài tập về nhà. Mã của tôi xây dựng tốt và ứng dụng chạy ổn cho đến khi tôi cố gắng thêm một nhiệm vụ mới vào danh sách. Tôi nhận được lỗi này Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c25719e8)trên dòng sau:ForEach(courses, id: \.self) { course in . Bảng điều khiển cũng có lỗi này : Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2823cb3a0>.

Tôi biết rất ít về Dữ liệu cốt lõi và không biết vấn đề có thể là gì. Tôi đã thiết lập các thực thể "Bài tập" và "Khóa học" trong mô hình dữ liệu, trong đó Khóa học có mối quan hệ một-nhiều với Bài tập. Mỗi bài tập sẽ được phân loại theo một khóa học cụ thể.

Đây là mã cho chế độ xem thêm một nhiệm vụ mới vào danh sách:

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

EDIT: Đây là mã trong AppDelegate thiết lập vùng chứa liên tục:

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

Và mã trong SceneDelegate thiết lập môi trường:

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

Nơi nào bạn thêm bối cảnh đối tượng được quản lý vào môi trường? Làm thế nào là bối cảnh đối tượng được quản lý được tạo ra? Có vẻ như bạn chưa kết nối nó với một điều phối viên cửa hàng liên tục,
Paulw11

Tôi đã thêm mã nơi tôi thêm moc vào môi trường trong bài viết gốc của tôi cho bạn.
Kevin Olmats

@KevinOlmats Câu trả lời của tôi có giúp được không?
Fulvio

Kiểm tra xem bạn đã chỉ định một bối cảnh thông qua môi trường.environment(\.managedObjectContext, viewContext)
onmyway133

@ onmyway133 đây là câu trả lời đúng
Kevin Olmats

Câu trả lời:


8

Bạn không thực sự tiết kiệm bối cảnh. Bạn nên thực hiện như sau:

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

Ngoài ra bạn @FetchRequest(...)có thể trông như thế này:

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

Bạn có thể sửa đổi CourseItemlớp của bạn để xử lý sortDescriptorsnhư sau:

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

Sau đó, bạn sẽ sửa đổi ForEach(...)như sau và cũng có thể xử lý việc xóa các mục khá dễ dàng:

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

Một điều bạn muốn đảm bảo là "Tên lớp" được đặt thành "CourseItem", khớp với CourseItemlớp chúng ta đã tạo trước đó.

Chỉ cần nhấp ĐƠN VỊ tại của bạn .xcdatamodeIdtập tin và thiết lập tất cả mọi thứ đến sau (bao gồm mô-đun để "Module sản phẩm hiện tại" và codegen là "Manual / Không"):

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.