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