CoreData - 删除托管对象内的对象
Posted
技术标签:
【中文标题】CoreData - 删除托管对象内的对象【英文标题】:CoreData - delete an object inside a managed object 【发布时间】:2015-07-02 17:11:48 【问题描述】:我正在使用 CoreData 在对话中保留消息列表。
Conversation 是一个 managedObject,它有一个 Messages 数组。 在一种情况下,我试图删除对话中的所有消息。
for (UQMessage * message in self.tempConversation.chatMessages)
[self.tempConversation.managedObjectContext deleteObject:message];
error = nil;
[self.tempConversation.managedObjectContext.persistentStoreCoordinator lock];
if (![self.tempConversation.managedObjectContext save:&error])
NSLog(@"Can't Delete! %@ %@", error, [error localizedDescription]);
return;
[self.tempConversation.managedObjectContext.persistentStoreCoordinator unlock];
当我检查时
self.tempConversation.chatMessages.count
没有任何变化。
当我尝试添加消息以及删除对话本身时,一切都运行良好。但我似乎无法删除一条消息。
由于我不是要删除托管对象本身,而是要删除其中的另一个对象,是否有可能这样做? 如果没有,反正周围呢?
编辑:
Messages 是 Conversation 中的一个 NSOrderedSet。 我发现这个作品(取自thread):
NSMutableOrderedSet *mutableItems = (NSMutableOrderedSet *)items.mutableCopy;
[mutableItems addObject:anItem];
items = (NSOrderedSet *)mutableItems.copy;
虽然我不确定这是否是要走的路。
【问题讨论】:
【参考方案1】:首先,关于 Matt S. 的回答,您没有修改 self.tempConversation,因此您不必担心在迭代时会改变数组。
另一方面,如果您的问题是 self.tempConversation.chatMessages.count 没有改变。这是正常的。您正在从 NSManagedObjectContext 中删除对象。但是数组没有被修改。因此,该数组仍然具有托管对象,但该托管对象已被删除。有那么容易吗。它是一个僵尸托管对象,因为它已从 MOC 中删除。然而,该对象尚未从数组中删除。因此,您有一个将属性已删除设置为 YES 的托管对象。而且它不再是 MOC 的一部分。
【讨论】:
OP 正在尝试修改 self.tempConversation.chatMessages。它不像从数组中纯粹删除项目那样简单,但是因为 OP 正在尝试快速枚举数组,锁定持久存储,将删除提交到关系,然后继续迭代关系数组,所以 OP 是在枚举数组时有效地尝试改变关系。 老实说,我很惊讶它没有崩溃,因为理论上当您提交这样的保存时,Core Data 会增加 MOC 的内部版本,并且应该将所有现有关系返回到故障对象以重新获取在第一次访问。我的猜测是快速枚举对对象进行了深层复制,因此试图保证不会崩溃。 @MattS。我不明白你为什么说 OP 试图模糊 self.tempConversation.chatMessages。没有任何修改该数组的操作。 这是代码试图做什么以及核心数据应该做什么的隐式突变。通过运行删除然后保存删除,如果快速枚举不是很好,则数组应该在下一次通过时包含不同的结果。 你在哪里找到隐式突变?如果 self.tempConversation.chatMessages 是一个数组或一个有序集合的副本,即使原始 i 由核心数据管理,也没有人在数组中删除或插入项目。【参考方案2】:你不应该,永远改变你正在迭代的数组。根据fast enumeration docs:“在枚举可变集合时删除、替换或添加到可变集合的元素是不安全的。如果您需要在枚举期间修改集合,您可以制作该集合的副本并使用副本进行枚举或在枚举期间收集您需要的信息,然后应用更改。”
在枚举期间改变数组的结果是不确定的,我的猜测是核心数据可能只是扔掉它的手而不做任何事情。可变副本起作用的原因是因为您正在处理副本,而不是您正在枚举的集合。
我会重写您的逻辑以遵循枚举文档中规定的准则,并在循环之外进行更改。
编辑:其他想法
为什么要锁定和解锁持久存储?它自己处理。
您可能可以在 for in 内部安全地调用 delete(但我不会),然后在外部调用 save,因为 save 是实际删除的内容。
更多想法
(从评论转录) - 在考虑了几天然后回来之后,我的猜测是你没有彻底崩溃的原因是快速枚举正在对你正在工作的关系数组进行深层复制on,因为在 MOC 上调用 save 会增加一个内部版本,然后 应该 将所有现有的托管对象返回给一个故障对象,以便在下次访问时重新获取。实际上,从“应用程序健康”的角度来看,您在此处获得的这段代码实际上非常危险。
【讨论】:
【参考方案3】:如果您查看核心数据关系的文档,我想您会发现更简单的做法是将关系的关系删除规则设置为“级联”。当您删除对话时,这将为您删除所有消息。这是参考:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW1
【讨论】:
假设 OP 想要删除与消息相关的原始对话 ;-)以上是关于CoreData - 删除托管对象内的对象的主要内容,如果未能解决你的问题,请参考以下文章
使用 Core Data 时,是不是保留非托管对象类及其托管对象版本