7

遇到一个有趣的小问题。我正在编写一种将数组过滤为唯一对象的方法:

- (NSArray*)distinctObjectsByAddress {
    NSSet* uniqueSet = [NSSet setWithArray:self];
    NSArray* retArray = [uniqueSet allObjects];

    return retArray;
}

并写了一个单元测试来检查:

- (void)testDistinctObjectsByAddress5 {
    Person* adam1 = [[Person alloc] initWithFirstName:@"adam" lastName:@"adam" andParent:nil];
    Person* adam2 = [[Person alloc] initWithFirstName:@"adam" lastName:@"adam" andParent:nil];

    testPersonArray = [NSArray arrayWithObjects:adam1,adam2, nil];

    NSArray* checkArray = [testPersonArray distinctObjectsByAddress];

    STAssertEquals([checkArray count], [testPersonArray count], @"Array %@ counts should match %@ %@",checkArray,adam1,adam2);
}

很简单。有趣的是,大约 80% 到 90% 的时间测试通过,但由于该distinctObjectsByAddress方法只返回一个对象,所以它经常失败。我已经能够将其追溯到[NSSet setWithArray:self]调用,但我也能够验证这两个人对象是两个不同的对象(至少它们具有不同的地址)。我假设这setWithArray:只是做一个基本的地址比较,但我不明白为什么它有时会产生两个像它应该的对象,有时只产生一个。

我刚刚尝试过的东西正在改变adam2,所以名字和姓氏不完全相同adam1。这似乎修复了错误。当对象在逻辑上相同时,这是否指向某种编译器优化?

4

2 回答 2

10

我假设 setWithArray 只是做一个基本的地址比较

这是不正确的。NSSet对添加到它的对象使用-isEqual:和方法。-hash这取决于这些是如何在 Person 或其超类中实现的。

如果[person1 isEqual:person2]那么您会期望该集合包含一个对象。如果不是,则该集合应包含两个对象。

我的猜测是 Person 不遵循其和方法中的规则。最有可能的是,这两个对象是相等的,但它们的哈希值并不像它们应该的那样相等。(除了你幸运的 10-20% 的时间。)-isEqual:-hash

当对象在逻辑上相同时,这是否指向某种编译器优化?

不,没有编译器优化可以将两个对象合并为一个。

于 2012-02-20T02:00:15.790 回答
3

很可能您没有实现hashfor Person,有时相同的Person对象散列到两个不同的存储桶中。

于 2012-02-20T01:51:04.873 回答