我需要确定一个对象是否包含在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执行得更好?
答案 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包含一些非常漂亮的优化。