Ios 存储对已删除NSManagedObject的引用的局部变量会发生什么情况
当我从数据库中删除Ios 存储对已删除NSManagedObject的引用的局部变量会发生什么情况,ios,core-data,nsmanagedobject,Ios,Core Data,Nsmanagedobject,当我从数据库中删除NSMangedObject时,分配给它的局部变量会发生什么情况 例如,我有一个简单的NSManagedObject: class MyManagedObject: NSManagedObject { @NSManaged var name: String } 然后在我的ViewController中,我将其从数据库中拉出,并在本地分配: class ViewController: UIViewController { var myManagedObject
NSMangedObject
时,分配给它的局部变量会发生什么情况
例如,我有一个简单的NSManagedObject:
class MyManagedObject: NSManagedObject {
@NSManaged var name: String
}
然后在我的ViewController中,我将其从数据库中拉出,并在本地分配:
class ViewController: UIViewController {
var myManagedObject: MyManagedObject!
}
然后我从数据库中删除它
如果打印对象名,我将在控制台中获得以下内容
print("myManagedObject.name = \(myManagedObject.name)")
//prints: "myManagedObject.name = "
好像物体不在那里?但是如果我把这个变量变成一个可选变量并检查它是否为nil,我会被告知它不是nil
我不太清楚如何在脑海中调和这一点。似乎有东西指向局部变量,但它的属性消失了
如果我有许多完全不同的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
}
}
}
因此,现在我将其从数据库中删除:
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
?它是一个空字符串吗?还是其他奇怪的元类型?您可能在这里寻找的主要内容是核心数据上下文。上下文是内存和实际数据库之间的连接
无论何时获取数据,都是通过上下文获取数据。这些是可以修改甚至删除的托管对象。在保存上下文之前,这些都不会在数据库中发生
当您删除一个对象时,该对象被标记为删除,但未从内存中删除,因为如果没有其他内容,上下文仍将使用该对象从数据库中实际删除该对象
一旦您调用删除托管对象,它会发生什么几乎是不相关的,即使它可能会更改,因为它是框架的一部分。因此,您有责任检查这些案例,并在需要时重新蚀刻对象。因此,您必须确保您的应用程序具有适当的体系结构,并负责任地使用核心数据
关于如何使用数据库,有很多种方法,其中或多或少都有一种独特的最佳使用方式。你需要更具体地说明你在做什么,你在哪里看到潜在的问题,这样我们才能让你走上正确的轨道
给你一个例子,考虑远程服务器的数据同步。在这里,无论用户在做什么或他是应用程序的哪一部分,都可以随时同步数据
为此,我建议您使用一个在单独线程上运行的上下文。从数据库中检索到所有托管对象后,应将其包装并复制其属性。在大多数实体上,您可能会遇到以下情况:MyEntity.findAll { items in
...the fetch happens on context thread and returns to main, items are wrappers
}
MyEntity.find(id: idString, { item in
...the fetch happens on context thread and returns to main, items are wrappers
})()
然后,由于您无法直接访问托管对象,因此需要某种方法将数据复制到托管对象,如:
myEntityInstance.commit() // Copies all the data to core data object. The operation is done on a context thread. A callback is usually not needed
然后保存数据库
MyEntity.saveDatabse {
... save happens on the context thread and callback is called on main thread
}
现在,聪明的部分是savedatabase
方法将向代理报告所做的更改。委托通常是当前视图控制器,因此有一个超类(如DataBaseViewController
)是有意义的,该超类在视图中出现时会将自身指定为委托MyEntity.delegate=self
,查看时确实加载了一些方法调用reloadData
,并且在databaseDidChange
中委托方法调用reloadData
,并且在视图中将出现相同的调用
现在,属于DataBaseViewController
子类的每个视图控制器都将覆盖reloadData
,并且在该方法中,您将再次从数据库获取数据。您正在获取所有项目或单个项目。因此,对于那些单个对象,您需要保存对象的id
,并通过该id
再次获取它。如果返回的对象是nil
,则项目已被删除,因此您可以抓住您似乎要提到的问题
所有这些都过于简单化了,但我希望您对核心数据以及如何使用它有一个基本的了解。这并不容易,过去从未如此,将来也很可能如此。它的设计是为了能够在尽可能短的时间内访问数据,即使是从一个非常大的数据库。结果是它可能不是很安全。您可能在这里寻找的主要内容是核心数据上下文。上下文是内存和实际数据库之间的连接
无论何时获取数据,都是通过上下文获取数据。这些是可以修改甚至删除的托管对象。在保存上下文之前,这些都不会在数据库中发生
当您删除一个对象时,该对象被标记为删除,但未从内存中删除,因为如果没有其他内容,上下文仍将使用该对象从数据库中实际删除该对象
一旦您调用删除托管对象,它会发生什么几乎是不相关的,即使它可能会更改,因为它是框架的一部分。因此,您有责任检查这些案例,并在需要时重新蚀刻对象。因此,您必须确保您的应用程序具有适当的体系结构,并负责任地使用核心数据
关于如何使用数据库,有很多种方法,其中或多或少都有一种独特的最佳使用方式。你需要更具体地说明你在做什么,你在哪里看到潜在的问题,这样我们才能让你走上正确的轨道
到gi
MyEntity.saveDatabse {
... save happens on the context thread and callback is called on main thread
}