5

我需要确定一个对象是否包含在 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 执行得更好?

4

2 回答 2

20

两者都不。您应该使用NSFetchRequest带有谓词的 an。您的模式可能会意外地破坏整个关系,这是非常昂贵的,并且不需要仅仅检查它是否包含一个对象。有一些方法可以小心谨慎,不要指责整个关系,但它很脆弱(搜索的微小变化会导致性能发生巨大变化),因此最好养成使用NSFetchRequest而不是集合进行搜索的习惯。在这些情况下,我喜欢将 my 设置fetchLimit为 1,因此一旦找到它,它就会停止查找。

为方便起见,您可能希望-containsFoo:在托管对象上创建一个方法,这样您就不必到处编写获取逻辑。

您上面的两个解决方案略有不同。第一个测试集合中是否存在isEqual:to的对象itemOfInterest。您的第二个解决方案测试集合中是否存在与itemOfInterest. 对于具有自定义isEqual:逻辑的对象,这些可以返回不同的结果。这意味着解决方案 2 对于非核心数据收集可能会稍微快一些,但这是因为您实际上是在测试不同的东西,而不是因为对象枚举。(实际上,这只适用于小型收藏;见下文。)

为什么您认为解决方案 1 使用-objectEnumerator

正如@James Raybould 指出的那样,出于性能原因,您通常不应该尝试重写内置方法。如果isEqual:解决方案 2 的某个版本比解决方案 1 更快,您会不会认为 Apple 会-containsObject:使用解决方案 2 中的代码来实现?

实际上,底层CFSet是作为散列实现的,因此检查包含是对数的而不是线性的。一般来说,对于具有合理散列函数的大集合,方案一会更快。请参阅CFSet.c中的代码。寻找CFSetContainsValue()。当然,不能保证 CFSet 的实现保持不变,但它有助于理解在 Cocoa 中通常如何解决性能问题。

于 2011-03-18T19:41:53.633 回答
5

我总是选择选项1。

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

于 2011-03-18T19:15:09.823 回答