为啥保存托管对象上下文更改 isDeleted 值?

Posted

技术标签:

【中文标题】为啥保存托管对象上下文更改 isDeleted 值?【英文标题】:Why saving managed object context changes isDeleted value?为什么保存托管对象上下文更改 isDeleted 值? 【发布时间】:2020-06-27 01:42:32 【问题描述】:

我正在使用 SwiftUI 和 Core Data 编写一个 ios 应用程序。我对 Core Data 很陌生,并试图理解一些东西:

为什么尝试 self.moc.save()self.item.isDeletedtrue 更改为 false ? 它发生在我删除核心数据对象(isDeleted 更改为 true)之后,但稍后保存托管对象上下文将其更改为 false。这是为什么呢?

这是一个例子:

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)
                
            
            
        
        
    

我预期会发生的事情:

    self.moc.delete(self.item) 将删除一个对象并将 self.item.isDeleted 标记为 true。 尝试 self.moc.save 将保存 moc if !self.item.isDeleted 如果项目被删除,将阻止代码执行(没有这个,我得到一个错误:Mutating a managed object (...) after it has been removed)

没有用。我在几行上添加了 print(self.item.isDeleted) 并在这些行上添加断点以检查到底发生了什么。

发生的事情是这样的:

    self.moc.delete(self.item) 删除了一个对象并将 self.item.isDeleted 标记为 true。 尝试 self.moc.save 保存的 moc 和... self.item.isDeleted 改为 false 如果 !self.item.isDeleted 没有阻止代码执行,因为此时 isDeleted 为 false。

这是一个错误吗?或者我不理解 Core Data 对象的生命周期和 isDeleted 的变化?

【问题讨论】:

删除 CoreData 实体后,无论如何都不应该更改它。你可以做的是,你为每个被删除的实体存储一个自己的值。当您想删除一个项目时,您只需将该布尔值更改为 true。然后你可以在你的 View/FetchRequest 的任何地方使用它。您必须小心,因为该实体没有被删除。您可以在一段时间后使用 isDeleted 删除对象。 谢谢,我已经用类似的方法解决了。我将@State private var itemExists = true 添加到DetailsView 中,删除后我正在更改它的值。 【参考方案1】:

为什么要尝试 self.moc.save() 将 self.item.isDeleted 从 true 更改为 错误的?它发生在我删除核心数据对象(isDeleted 更改 为 true),但稍后保存托管对象上下文会将其更改为 false。 这是为什么呢?

它的行为与记录相同 - 返回 true before 保存,而不是在其他情况下

这是NSManagedObject 的 Apple 文档快照:

总结

一个布尔值,指示托管对象是否 在下次保存期间删除。声明

var isDeleted: Bool get Discussion

如果 Core Data 将要求持久存储删除对象,则为 true 在下一次保存操作期间,否则为假。它可能返回 false 在其他时候,尤其是在对象被删除之后。这 它将停止返回 true 的即时性取决于 对象正在被删除。如果接收器有故障, 访问此属性不会导致它触发。

【讨论】:

以上是关于为啥保存托管对象上下文更改 isDeleted 值?的主要内容,如果未能解决你的问题,请参考以下文章

核心数据单一托管对象上下文和两个线程

NSManagedObject 保存后更改了属性

托管对象上下文未保存到持久存储

更新当前的 CoreData 条目

Core Data 托管对象上下文线程同步

为啥委托方法需要将自定义类托管对象上下文的内容保存在委托类托管对象上下文中?