NSSet 的 containsObject 和快速枚举哪个更好?
我需要确定一个对象是否包含在核心数据对多关系(即 NSSet)中,并且我试图确定两个解决方案中哪一个更好:
解决方案 1)
if ([managedObject.items containsObject:itemOfInterest])
return …
解决方案 2)
for (NSManagedObject *item in managedObject.items)
if ([item == itemOfInterest])
return …
解决方案 1 更简洁,但是 NSSet Class Ref 说快速枚举比 NSSet 的 objectEnumerator 性能更好。它的性能是否也比 containsObject 更好?
I need to determine whether an object is included in a Core Data to-many relationship (which is an NSSet), and I’m trying to decide which of two solutions is better:
Solution 1)
if ([managedObject.items containsObject:itemOfInterest])
return …
Solution 2)
for (NSManagedObject *item in managedObject.items)
if ([item == itemOfInterest])
return …
Solution 1 is more concise, but the NSSet Class Ref says fast enumeration performs better than NSSet’s objectEnumerator. Does it also perform better than containsObject?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
两者都不。您应该将
NSFetchRequest
与谓词一起使用。您的模式可能会意外地破坏整个关系,这是非常昂贵的,并且不需要仅仅检查它是否包含一个对象。有一些方法可以小心,不要破坏整个关系,但它很脆弱(搜索的微小变化会导致性能的巨大变化),因此最好养成使用NSFetchRequest
的习惯,而不是用于搜索的集合。在这些情况下,我喜欢将fetchLimit
设置为 1,这样一旦找到它,它就会停止查找。为了方便起见,您可能希望在托管对象上创建一个
-containsFoo:
方法,这样您就不必到处编写获取逻辑。您上面的两个解决方案略有不同。第一个测试集合中是否存在
isEqual:
到itemOfInterest
的对象。您的第二个解决方案测试集合中是否存在与itemOfInterest
位于同一内存位置的对象。对于具有自定义isEqual:
逻辑的对象,它们可能返回不同的结果。这意味着解决方案 2 对于非核心数据收集可能会稍微快一些,但这是因为您实际上正在测试不同的东西,而不是因为对象枚举。 (实际上,这仅适用于小型集合;请参见下文。)您为什么认为解决方案 1 使用
-objectEnumerator
?正如 @James Raybould 指出的那样,出于性能原因,您通常不应尝试重写内置方法。如果解决方案 2 的
isEqual:
版本比解决方案 1 更快,您是否认为 Apple 会使用解决方案 2 中的代码实现-containsObject:
?实际上,底层
CFSet
是作为哈希实现的,因此检查包含性是对数的而不是线性的。一般来说,对于具有合理哈希函数的大型集合,解决方案 1 会更快。请参阅 CFSet.c 中的代码。查找CFSetContainsValue()
。当然,CFSet 的实现不能保证保持不变,但它对于理解 Cocoa 中通常如何解决性能问题很有用。Neither. You should use an
NSFetchRequest
with a predicate. Your patterns can accidentally fault the entire relationship, which is very expensive and not needed just to check for whether it contains one object. There are ways to be careful and not fault the entire relationship, but it's fragile (small changes to your search lead to huge changes in performance) and so it's better to be in the habit of usingNSFetchRequest
rather than the collection for searching. I like to set myfetchLimit
to 1 in these cases so once it finds it, it stops looking.For convenience, you may want to create a
-containsFoo:
method on your managed object so you don't have to write the fetch logic all over the place.Your two solutions above are subtly different. The first one tests whether there is an object in the collection that
isEqual:
toitemOfInterest
. Your second solution tests whether there is an object in the collection at the same memory location asitemOfInterest
. For objects with customisEqual:
logic, these can return different results. This means that solution 2 might be slightly faster for non-core data collections, but it's because you're actually testing a different thing, not because of object enumeration. (In reality, this is only true for small collections; see below.)Why do you believe that solution 1 uses
-objectEnumerator
?As @James Raybould points out, you generally should not try to rewrite the built-in methods for performance reasons. If an
isEqual:
version of Solution 2 were faster than Solution 1, wouldn't you think Apple would have implemented-containsObject:
using the code in solution 2?In reality, the underlying
CFSet
is implemented as a hash, so checking for containment is logarithmic rather than linear. Generally speaking, for large sets with reasonable hash functions, solution 1 will be faster. See the code for it in CFSet.c. Look forCFSetContainsValue()
. CFSet's implementation isn't guaranteed to stay the same, of course, but it's useful for understanding how performance concerns are generally addressed within Cocoa.我总是选择选项 1。
它更简洁,我可以准确地告诉您尝试对代码做什么,并且 containsObject 可能包含一些非常漂亮的优化。
I'd always go for option 1.
Its more concise, I can tell exactly what your trying to do with the code and chances are that the containsObject contains some pretty nifty optimisations.