I am writing an iOS app using SwiftUI and Core Data. I am very new to Core Data and try to understand something:
Why try self.moc.save() changes self.item.isDeleted from true to false? It happens after I delete a Core Data object (isDeleted changes to true), but later saving managed object context changes it to false. Why is that?
Here is an example:
ContentView.swift
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
var fetchRequest: FetchRequest<Item>
var items: FetchedResults<Item> { fetchRequest.wrappedValue }
var body: some View {
NavigationView {
List {
ForEach(items, id: \.self) {item in
NavigationLink(destination: DetailsView(item: item)) {
Text("\(item.name ?? "default item name")")
}
}
}
.navigationBarTitle("Items")
.navigationBarItems(
leading:
Button(action: {
for number in 1...3 {
let item = Item(context: self.moc)
item.date = Date()
item.name = "Item \(number)"
do {
try self.moc.save()
}catch{
print(error)
}
}
}) {
Text("Add 3 items")
}
)
}
}
init() {
fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \Item.name, ascending: true)
])
}
}
DetailsView.swift
import SwiftUI
struct DetailsView: View {
@Environment(\.managedObjectContext) var moc
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var item: Item
var body: some View {
VStack {
Text("\(item.name ?? "default item name")")
}
.navigationBarItems(
trailing:
Button(action: {
self.moc.delete(self.item)
print(self.item.isDeleted)
self.presentationMode.wrappedValue.dismiss()
print(self.item.isDeleted)
do {
try self.moc.save()
print(self.item.isDeleted)
}catch{
print(error)
}
}) {
Text("Delete")
.foregroundColor(.red)
}
)
.onDisappear {
print(self.item.isDeleted)
if !self.item.isDeleted {
print(self.item.isDeleted)
self.item.name = "new name"
print(self.item.isDeleted)
do {
try self.moc.save()
}catch{
print(error)
}
}
}
}
}
What I expected will happen:
- self.moc.delete(self.item) will delete an object and mark self.item.isDeleted as true.
- try self.moc.save will save moc
- if !self.item.isDeleted will prevent code execution if item is deleted (without this, I was getting an error: Mutating a managed object (...) after it has been removed)
It didn't work. I have added print(self.item.isDeleted) on few lines and breakpoints on those lines to check what exactly happens.
What happened is this:
- self.moc.delete(self.item) deleted an object and marked self.item.isDeleted as true.
- try self.moc.save saved moc and...
- self.item.isDeleted changed to be false
- if !self.item.isDeleted didn't prevent code execution, because isDeleted was false at this point.
Is it a bug? Or I don't understand the life cycle of Core Data objects and isDeleted changes as it should?