哪个更好,NSSet的containsObject或快速枚举?

时间:2011-03-18 19:10:47

标签: objective-c core-data nsset

我需要确定一个对象是否包含在Core Data to-many关系中(这是一个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执行得更好?

2 个答案:

答案 0 :(得分:20)

都不是。您应该使用带有谓词的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中通常如何解决性能问题。

答案 1 :(得分:5)

我总是选择选项1.

它更简洁,我可以准确地告诉您尝试使用代码做什么,并且很有可能containsObject包含一些非常漂亮的优化。