【发布时间】:2017-05-05 05:45:24
【问题描述】:
当我从数据库中删除 NSMangedObject 时,分配给它的局部变量会发生什么情况?
例如,我有一个简单的 NSManagedObject:
class MyManagedObject: NSManagedObject {
@NSManaged var name: String
}
然后在我的 ViewController 中,我将其从数据库中拉出,并在本地分配:
class ViewController: UIViewController {
var myManagedObject: MyManagedObject!
}
然后我从数据库中删除它。
如果打印对象名称,我会在控制台中得到以下内容
print("myManagedObject.name = \(myManagedObject.name)")
//prints: "myManagedObject.name = "
好像对象不存在一样?但是,如果我将变量转换为可选项并检查它是否为零,我会被告知它不是零。
我不太确定如何在我的脑海中调和这一点。似乎有一些东西指向了局部变量,但它的属性已经消失了。
如果我有许多不同的 UI 对象依赖于该对象的属性,我不能假设内存中存在它的一些本地深层副本?
这里是更完整的代码:
在 viewDidLoad 我创建新对象,保存上下文,获取对象,然后在本地分配它。
class ViewController: UIViewController {
var myManagedObject: MyManagedObject!
override func viewDidLoad() {
super.viewDidLoad()
//1 Create the new object
let newObject = NSEntityDescription.insertNewObject(forEntityName: "MyManagedObject", into: coreDataManager.mainContext) as! MyManagedObject
newObject.name = "My First Managed Object"
//2 Save it into the context
do {
try coreDataManager.mainContext.save()
} catch {
//handle error
}
//3 Fetch it from the database
let request = NSFetchRequest<MyManagedObject>(entityName: "MyManagedObject")
do {
let saved = try coreDataManager.mainContext.fetch(request)
//4 Store it in a local variable
self.myManagedObject = saved.first
} catch {
//handle errors
}
}
}
此时如果我打印局部变量的name 属性,我会得到正确的响应:
print("The object's name is: \(myManagedObject.name)")
//prints: The object's name is: My First Managed Object
所以,现在我从数据库中删除它:
if let storedObject = myManagedObject {
coreDataManager.mainContext.delete(storedObject)
do {
try coreDataManager.mainContext.save()
} catch {
//handle error
}
}
但是现在,当我打印时,我得到了最奇怪的输出:
print("myManagedObject.name = \(myManagedObject.name)")
//prints: "myManagedObject.name = "
这完全不是我期望记忆的工作方式。如果我创建一个类Foo 的实例,然后将该实例传递给不同的对象,那么它就是同一个实例。只有当没有人指向它时它才会消失。
在这种情况下——变量myManagedObject是什么?这不是nil。字符串name 是什么?它是一个空字符串吗?还是其他一些奇怪的元类型?
【问题讨论】:
-
显示您在本地“分配”它的代码。 var myManagedObject: MyManagedObject!只会“制作”一个 MyManagedObject 类型的新变量
-
由于您的问题更新:删除托管对象后将其标记为已删除,并在保存数据库后将其从数据库中删除(不在内存中)。在托管对象上,您应该检查 isDeleted 属性甚至“故障”属性。正如您预测的那样,该对象在内存中持续存在,但在您的情况下它的行为是不可预测的。根据框架的变化,任何事情都可能发生,空字符串似乎是一个很好的解决方法,它仍然可以工作。删除后不要使用此对象是您的工作。
-
但是兔子洞更深了。如果您使用多个上下文并在一个上下文中删除该对象,它仍将存在于另一个上下文中。但是,一旦您尝试在第二个上下文中应用更改,就会报告您需要解决的冲突。因此,在内存中,每个上下文都有一个实例,这些实例将保留在内存中,直到 ARC 规则决定释放它。但是它的属性可以随时改变。因此,该对象仍然存在,但其属性不可访问。无论如何,它应该崩溃,但似乎已经为您处理了异常。
-
@MatikOblak - 我相信以上两个 cmets 是我一直在寻找的答案。如果您想将它们移至您的答案,我会将其标记为已接受。事实上,检查 isFault 属性告诉我我需要知道什么,尽管我仍然不清楚为什么我不崩溃。在不崩溃的情况下找到错误将非常困难!我尝试检查 name == "" 是否正确,所以 CoreData 给了我一个空字符串……哎呀!我还认为,正如您所建议的那样,在我的情况下,复制内存中的内容最适合我的使用。谢谢。
-
由于您的问题不是关于如何检测已删除的托管对象,所以我们就保持这种方式。关于发现错误:您是否尝试过覆盖 setter?如果您确保研究如何在核心数据中做到这一点。尽管在您的情况下,您可能想要覆盖并将断点设置到故障设置器中,以找出删除它的原因。仍然可能行不通,如果不行,您需要添加观察者。
标签: ios core-data nsmanagedobject