NSManagedObject 作为 NSDictionary 键?
在我的应用程序中,我有一个 NSDictionary,其键应该是 NSManagedObject 子类的实例。
然而,问题在于 NSManagedObject
没有实现 NSCopying
协议,这意味着 NSManagedObject
的核心数据对象/实例不能用作字典键,即使 -[hash]
方法对它们来说效果很好。
我应该做什么?
In my app, I have a NSDictionary
whose keys should be instances of a subclass of NSManagedObject
.
The problem, however, is that NSManagedObject
does not implement the NSCopying
protocol which means that no Core Data objects / instances of NSManagedObject
can be used as dictionary keys even though the -[hash]
method works fine for them.
Was should I do?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
有四个选项:
[object objectID]
或+[NSValue valueWithNonretainedObject:]
似乎是最明显的CFDictionaryCreateMutable()
创建一个带有 retained< 的字典/em> 键,而不是复制,然后调用CFDictionarySetValue()
来存储对象[NSMapTable mapTableWithStrongToStrongObjects]
为您提供纯粹的 Objective -C 相当于CFMutableDictionary
NSCopying
,以便它返回 self(如果您不使用 ARC,则具有增加的引用计数
) +valueWithNonretainedObject: 非常危险,因为可能会留下悬空指针;可能最好避免。
存储对象 ID 很好,除了新对象以临时 ID 开始生命这一事实之外。当上下文保存到磁盘时(或调用
-obtainPermanentIDsForObjects:...
),该 ID 将更改为永久 ID。您的映射代码需要足够智能才能处理此问题,除非它可以保证所有传入对象都已经具有永久 ID。像这样实现 NSCopying 感觉有点恶心,但应该可以正常工作。碰巧,这正是 NSURLSessionTask 所采用的方法,我认为是为了字典友好性。
在 OS X 10.8 Mountain Lion 之前,可以创建常规
NSMutableDictionary
,然后为其调用CFDictionarySetValue()
。但现在情况不再是这样了;新字典现在在 CF 级别指定了正确的复制回调,而不是纯粹是 NSMutableDictionary 的一个功能。There are four options:
[object objectID]
or+[NSValue valueWithNonretainedObject:]
seem the most obviousCFDictionaryCreateMutable()
to create a dictionary with retained keys, rather than copied, instead, and then callCFDictionarySetValue()
to store the objects[NSMapTable mapTableWithStrongToStrongObjects]
gives you a purely Objective-C equivalent toCFMutableDictionary
NSCopying
for your managed object subclass, such that it returns self (with a bumped reference count if you're not using ARC)Notes
+valueWithNonretainedObject:
is pretty dangerous, since it's possible to be left with a dangling pointer; likely best to avoid.Storing object IDs is fine, apart from the fact that new objects start out life with a temporary ID. That ID then changes to a permanent one when the context is saved to disk (or
-obtainPermanentIDsForObjects:…
is called). Your mapping code needs to be smart enough to handle this unless it can guarantee that all incoming objects already have a permanent ID.Implementing
NSCopying
like this feels a bit icky, but should work just fine. As it happens, this is exactly the approachNSURLSessionTask
takes, I presume for dictionary friendliness.Prior to OS X 10.8 Mountain Lion, it used to be possible to create a regular
NSMutableDictionary
and then callCFDictionarySetValue()
for it. That's no longer the case though; new dictionaries now have proper copy callbacks specified down at the CF level, rather than purely being a feature ofNSMutableDictionary
.我建议使用 [[[myManagedObject objectID] URIRepresentation]absoluteString] 作为密钥。
I suggest to use [[[myManagedObject objectID] URIRepresentation] absoluteString] as your key.
您可以创建一个包装类,其中包含对要用作字典键的 NSManagedObject 实例的引用吗?然后,您可以使此包装器类实现 NSCopying 以及哈希方法(可能只是调用 NSManagedObject 的哈希方法),并使用此包装器作为字典键。
Could you create a wrapper class, that contains a reference to the instance of NSManagedObject that you want to use as a dictionary key? You could then make this wrapper class implement NSCopying, along with a hash method (perhaps just calling the NSManagedObject's hash method), and use this wrapper as the dictionary key.
我遇到了类似的问题,其中我需要将多个实体与每个实体的附加数据捆绑在一起,并最初尝试:
由于上述原因(NSCopying),这不起作用,所以我这样做了:
但只有当您不这样做时,这个解决方案才有意义不需要以字典方式访问这些实体,或者很乐意迭代以找到您需要的内容。就我而言,这是一个包装问题。请注意,如果您在 NSManagedObjectContext 周围传递这些实体,则需要相同才能使用它们。
I had a similar problem, in which I needed to bundle several entities with additional data for each, and initially tried:
this didn't work for the reason above (NSCopying), so I did:
But this solution makes sense only if you don't need dictionary style access to these entities or are happy to iterate to find what you need. In my case this was a packaging problem. Note that if you pass these entities around the NSManagedObjectContext need to be the same to use them.