Estou tentando me ensinar os principais dados criando um aplicativo de gerenciamento de tarefas. Meu código é bom e o aplicativo funciona bem até eu tentar adicionar uma nova atribuição à lista. Eu recebo este erro Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c25719e8)
na seguinte linha: ForEach(courses, id: \.self) { course in
. O console também tem este erro: Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2823cb3a0>
.
Sei muito pouco sobre o Core Data e não sei qual será o problema. Eu configurei as entidades "Atribuição" e "Curso" no modelo de dados, onde o Curso tem um relacionamento um-para-muitos com a Atribuição. Cada tarefa será categorizada em um curso específico.
Este é o código para a exibição que adiciona uma nova atribuição à lista:
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: Aqui está o código no AppDelegate que configura o contêiner persistente:
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
}()
E o código no SceneDelegate que configura o ambiente:
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)
Respostas:
Você não está realmente salvando o contexto. Você deve executar o seguinte:
Além disso, você
@FetchRequest(...)
pode ficar assim:Você pode modificar sua
CourseItem
classe para lidarsortDescriptors
com o seguinte:Então você modificaria o seu
ForEach(...)
como o seguinte e também poderá lidar com a exclusão de itens com bastante facilidade:Uma coisa que você deseja garantir é que o "Nome da classe" esteja definido como "CourseItem", que corresponde à
CourseItem
classe que criamos anteriormente.Simplesmente clique em ENTIDADES no seu
.xcdatamodeId
arquivo e defina tudo para o seguinte (incluindo Módulo para "Módulo atual do produto" e Codegen para "Manual / Nenhum"):fonte