NSSet 包含具有被覆盖的 isEqual 的对象

NSSet containing objects with overwritten isEqual

在我的 class 中,我覆盖了 isEqual

@interface MyClass : NSObject

@property (nonatomic, strong) NSString * customID;

@end

我覆盖了 isEqual 所以它只检查 customID

的相等性
- (BOOL)isEqual:(id)object {

    if ([object isKindOfClass:[MyClass class]]) {
        if (self.customID == nil) {
            return NO;
        }
        return [self.customID isEqual:[object customID]];
    }
    return [super isEqual:object];
}

现在 NSSet 实际上是一个散列 table,如果它包含散列值,可以快速检查它...这就是我们所知道的

但是,让我们想象一下这段代码

NSArray * instancesToCheck = ...;
NSArray * allInstances = ...;

for (MyClass * instance in allInstances) {

    if ([instancesToCheck containsObject:instance]) {
        // do smth
    }

}

我想 "optimize" 这个(使用 NSSet 进行成员测试)

NSArray * instancesToCheck = ...;
NSArray * allInstances = ...;

NSSet * instancesToCheckAsSet = [NSSet setWithArray:instancesToCheck];

for (MyClass * instance in allInstances) {

    if ([instancesToCheckAsSet containsObject:instance]) {
        // do smth
    }

}

第二个代码是否提供任何性能优势(假设创建它的数组中没有重复项,并且 instancesToCheck 包含不同的指针,但一些对象具有相同的 customID,使得 isEqual==YES 但指针比较==NO)?

当我查看文档时,我发现 containsObject 调用了 isEqual,因此无论如何它都必须遍历所有对象

将 NSSet 与对象一起使用时,覆盖 isEqual 对性能有何影响?变成NSSet那么效率低了?

Does the second code provide any performance benefit at all

当然可以。数组必须循环检查每个对象的数组。一个集合或多或少立即知道一个对象是否被包含,因为它是一个散列table。事实上,这种东西正是集合 for.

您必须覆盖 hash,如果您覆盖 isEqual: 否则可能会破坏功能并且可能无法按预期运行

被视为 "equal" 的两个对象必须 return 具有相同的哈希值。

- (BOOL)isEqual:(id)object {

    if ([object isKindOfClass:[MyClass class]]) {
        if (self.customID == nil) {
            return NO;
        }
        return [self.customID isEqual:[object customID]];
    }
    return [super isEqual:object];
}

// MUST overwrite hash

- (NSUInteger)hash {
    return [self.customID hash];
}