遇到了一个有趣的小问题。我正在写一个方法来过滤一个数组到唯一的对象:
- (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
不完全相同。这似乎修复了错误。当对象在逻辑上相同时,这是否指向某种编译器优化?
我假设setWithArray只是在做一个基本的地址比较
这是不正确的。NSSet在添加到它的对象上使用-isEqual:
和-hash
方法。这取决于这些方法在Person或其超类中的实现方式。
如果是[person1 isEqual:person2]
,那么您希望该集合包含一个对象。如果不是,则该集合应包含两个对象。
我的猜测是Person没有遵循其-isEqual:
和-hash
方法中的规则。最有可能的是,这两个对象是相等的,但它们的哈希值并不像应该的那样相等。(除了10-20%的时间你很幸运。)
当对象在逻辑上相同时,这是否指向某种编译器优化?
不,没有编译器优化可以将两个对象合并为一个。
很可能您没有为Person
实现hash
,有时相同的Person
对象会散列到两个不同的桶中。