如何在关系变空时删除托管对象
Posted
技术标签:
【中文标题】如何在关系变空时删除托管对象【英文标题】:How to Delete a Managed Object When a Relationship Becomes Empty 【发布时间】:2011-08-22 18:38:26 【问题描述】:我目前正在为 iPhone 开发我的第一个 Core Data 项目。在进行了一些实验之后,我对核心数据中的实体关系有一些相当基本的问题。
假设我有两个实体:事件和位置。他们每个人都有一个名称属性。一个事件只能有一个位置,而一个位置可以有多个事件。所以关系应该是这样的:
Event <<--> Location
在我的项目中,我(用户)可以输入事件的名称及其位置。然后我根据该输入为 Event 实体创建一个新对象。我通过像这样访问事件的关系来设置位置的名称:
event.Location.name = someCustomString;
保存工作正常。我想。
我的第一个问题是:
Core Data 是否每次我这样做时都会为 Location 实体创建一个新对象 - 即使之前使用过相同的 Location 名称(并且仍然存储)?或者在这种情况下,核心位置是否自动仅将关系设置为现有的位置对象?因为对于我的项目,有必要识别发生在同一地点的事件。
这也引出了我的下一个问题:
如果删除一个 Event 对象呢?当我这样做时,我必须检查相应的位置是否被多个事件使用。如果是,我将取消关系但保留 Location 对象。如果没有,我也必须删除 Location 对象。我目前的方法(基于我假设同名的位置不会被双重保存)如下所示:
Event *event = (event *)[appManager.results.fetchedObjects objectAtIndex:indexPath.row];
NSInteger locationEvents = 0;
for (Event *eve in appManager.results.fetchedObjects)
if (eve.Location.name == event.Location.name)
locationMoments++;
if (locationMoments == 1)
[appManager.managedObjectContext deleteObject:event.Location];
[appManager.managedObjectContext deleteObject:event];
所以至少我认为我正在检查某个 Location 对象所引用的事件数量。但是代码感觉有点痒......我不知道这是否是正确的方法。所以我的最后一个问题是: 在我的场景中,标准程序是什么?如果有的话。 ;)
提前谢谢大家的回答!!
【问题讨论】:
【参考方案1】:Core Data 是否每次都为 Location 实体创建一个新对象 我这样做
不,event.Location.name
是一个键路径,它将关系从Event
实例“遍历”到Location
实例,然后访问属性name
。键路径仅适用于现有对象。
但是,由于您有一个 Location
对象与许多 Event
对象共享,因此使用任何一个 Event
对象更改 Location.name
值会更改共享该 Location
对象的所有 Event
对象的值.
如果您希望托管对象在关系变为空时立即删除自身,则将删除代码放在类的remove…
访问器方法中。当关系为零时,让对象告诉上下文删除它。这样一来,您就可以将代码放在一个地方,而不是分散在任何可能会改变关系的地方。
如果您只想在保存上下文时删除对象,请将代码放在类的willSave
方法中。这将在下次保存上下文时触发删除。
【讨论】:
您说键路径仅适用于现有对象。但是当我第一次创建一个事件并使用该事件的位置名称时 - 必须创建一个新的 Location 对象,不是吗?从那一刻起,具有相同 Location.name 的事件会自动共享它吗?只是问问。我真的很想知道引擎盖下发生了什么。 :) 您在空关系上删除 Location 对象的方法听起来是正确的。我必须调查一下!我的代码示例有资格这样做吗?或者您通常如何在这种情况下检查现有关系?非常感谢您的回答! 创建Event
对象不会自动创建Location
对象,它只会在Event
对象中创建一个空的Event.location
属性。您必须将新的或现有的 Location
对象分配给关系。要检查空关系,只需计算对象的数量,例如[self.location count]==0
好的,我现在明白了。现在我也意识到问题在于我保存实体的方式。现在,每次创建新的 Event 对象时,我都会创建一个新的 Location 对象。 (认为 Core Data 可能会自动检查重复项。)相反,我应该检查一个现有的 Location 对象,该对象可能包含与当前输入的名称相同的名称。然后我将其链接到我的新活动。为此,我必须使用一些谓词为 Location 对象创建一个获取请求,对吗? ...再次感谢您的帮助,TechZen!
在核心数据中,只有在托管对象本身中保证是唯一的。每个对象仅由作为 UUID 的 managedObjectID 唯一标识。您可以拥有任意数量的托管对象,它们都具有完全相同的属性(尽管它们的关系是唯一的,因为相关对象是唯一的。)您确实需要执行提取或缓存现有的 Location
对象。【参考方案2】:
非常感谢您对 TechZen 的帮助。现在我想我对 Core Data 有了更好的理解。我也让我的数据模型正常工作。事实证明,当我创建实体和适当的子类时,我忘记将实体的类设置为检查器中创建的文件。 (以为会自动设置 - 因为文件也是自动创建的。)所以我的 Location 实体的 willSave 方法从未被调用过。我解决了这个问题并整理了如何以正确的方式处理关系。正如我所说,我使用带有简单“name == %@”谓词的 fetch 请求来查找以前使用的位置名称。 ;)
但毕竟我也在使用实际的位置数据(纬度、经度)。即使 Location 和它的名称相同,Location 的坐标也会略有不同。所以我必须找到一种方法来将存储的坐标与当前用户位置的坐标进行比较。当用户在以前使用的位置附近并且也使用那个人的名字时 - 那么新的坐标数据应该覆盖旧的 - 或者它应该被单独留下并且新的事件被分配给旧的位置。如果您对此有任何想法,我也将不胜感激!但我想我知道该怎么做——主要是。 :)
【讨论】:
以上是关于如何在关系变空时删除托管对象的主要内容,如果未能解决你的问题,请参考以下文章