CoreData and SwiftUI: Context in environment is not connected to a persistent store coordinator
Environment values like your moc are automatically passed only to other views in the hierarchy. So if you show a sheet or anything that is not part of your view hierarchy you'll lose the environment and you will need to pass the moc to the new hierarchy, like you did for ContentView. Check this code snippet:
.sheet(isPresented: self.$showSheet) {
SheetView()
.environment(\.managedObjectContext, self.moc)
}
You're not actually saving the context. You should be executing the following:
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)
}
Also your @FetchRequest(...)
could look like this:
@FetchRequest(fetchRequest: CourseItem.getCourseItems()) var courses: FetchedResults<CourseItem>
You can modify your CourseItem
class to handle the sortDescriptors
like the following:
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
}
}
Then you would modify your ForEach(...)
like the following and can also handle the deletion of items quite easily as well:
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)
}
}
One thing you want to ensure is that the "Class Name" is set to "CourseItem", which matches the CourseItem
class we created earlier.
Simply click ENTITIES in your .xcdatamodeId
file and set everything to the following (including Module to "Current Product Module" and Codegen to "Manual/None"):