J'essaie d'enseigner moi-même les données de base en créant une application de gestion des devoirs. Mon code fonctionne correctement et l'application fonctionne correctement jusqu'à ce que j'essaie d'ajouter une nouvelle affectation à la liste. Je reçois cette erreur Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c25719e8)
sur la ligne suivante: ForEach(courses, id: \.self) { course in
. La console a aussi cette erreur: Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2823cb3a0>
.
Je sais très peu de choses sur Core Data et je ne sais pas quel pourrait être le problème. J'ai configuré des entités "Affectation" et "Cours" dans le modèle de données, où Cours a une relation un-à-plusieurs avec Affectation. Chaque devoir sera classé dans un cours particulier.
Voici le code de la vue qui ajoute une nouvelle affectation à la liste:
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: Voici le code dans AppDelegate qui configure le conteneur persistant:
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
}()
Et le code de SceneDelegate qui configure l'environnement:
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()
}
}
.environment(\.managedObjectContext, viewContext)
Réponses:
Vous ne sauvegardez pas réellement le contexte. Vous devez exécuter les éléments suivants:
Vous
@FetchRequest(...)
pourriez également ressembler à ceci:Vous pouvez modifier votre
CourseItem
classe pour gérersortDescriptors
les éléments suivants:Ensuite, vous pouvez modifier votre
ForEach(...)
comme ceci et vous pouvez également gérer la suppression d'éléments assez facilement:Vous devez vous assurer que le "Nom de classe" est défini sur "CourseItem", ce qui correspond à la
CourseItem
classe que nous avons créée précédemment.Cliquez simplement sur ENTITIES dans votre
.xcdatamodeId
fichier et définissez tout sur les éléments suivants (y compris Module sur "Module de produit actuel" et Codegen sur "Manuel / Aucun"):la source