CoreData ve SwiftUI: Ortamdaki bağlam, kalıcı bir mağaza koordinatörüne bağlı değil


10

Bir ev ödevi yönetme uygulaması oluşturarak kendime Temel Verileri öğretmeye çalışıyorum. Benim kod iyi inşa ve ben listeye yeni bir atama eklemek çalışıncaya kadar uygulama iyi çalışır. Bu hatayı alıyorum Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c25719e8)aşağıdaki satırda: ForEach(courses, id: \.self) { course in. Konsol de bu hata var: Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2823cb3a0>.

Temel Veriler hakkında çok az şey biliyorum ve sorunun ne olabileceği konusunda kayboluyorum. Veri modelinde, Kursun Atama ile bir-çok ilişkisi olduğu "Atama" ve "Ders" varlıkları kurdum. Her ödev belirli bir kurs altında kategorize edilecektir.

Bu, listeye yeni bir ödev ekleyen görünümün kodudur:

    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: İşte kalıcı kapsayıcıyı ayarlayan AppDelegate kodu:

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

Ve SceneDelegate'teki ortamı ayarlayan kod:

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

Yönetilen nesne içeriğini çevreye nereye eklersiniz? Bu yönetilen nesne içeriği nasıl oluşturulur? Kalıcı bir mağaza koordinatörü ile bağlantınız yok gibi görünüyor,
Paulw11

Kodu sizin için orijinal yazımda çevreye eklediğim kodu ekledim.
Kevin Olmats

@KevinOlmats Cevabım yardımcı oldu mu?
fulvio

Ortam yoluyla bir bağlam atadığınızı kontrol edin.environment(\.managedObjectContext, viewContext)
onmyway133

@ onmyway133 bu doğru cevap
Kevin Olmats

Yanıtlar:


8

Aslında içeriği kaydetmiyorsunuz. Aşağıdakileri yürütüyor olmalısınız:

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

Ayrıca @FetchRequest(...)şöyle görünebilir:

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

CourseItemSınıfınızı aşağıdakileri işlemek için değiştirebilirsiniz 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
    }
}

Daha sonra ForEach(...)aşağıdakini değiştirirsiniz ve öğelerin silinmesini de kolayca gerçekleştirebilirsiniz:

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

Sağlamak istediğiniz bir şey, "Sınıf Adı" nın CourseItemdaha önce oluşturduğumuz sınıfla eşleşen "CourseItem" olarak ayarlanmış olmasıdır .

Basitçe tıklayın varlıkları sizin de .xcdatamodeId(dahil aşağıdakilere dosya ve ayar her şeyi Modülü "Mevcut Ürün Modülü" ve Codegen "Manuel / Yok" olarak):

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.