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);
}

ものすごく単純。distinctObjectsByAddress興味深いのは、メソッドがオブジェクトを 1 つしか返さないため、約 80 ~ 90% の確率でテストが成功し、場合によっては失敗することです。通話までたどることができました[NSSet setWithArray:self]が、2 人の人物オブジェクトが 2 つの異なるオブジェクトであることも確認できました (少なくとも、アドレスは異なります)。基本的なアドレス比較を行ってsetWithArray:いるだけだと思いますが、2つのオブジェクトを生成する場合と1つだけを生成する場合がある理由がわかりません。

私が試したのはadam2、名前と姓が とまったく同じにならないように変更していたことadam1です。これはエラーを修正するようです。オブジェクトが論理的に同じである場合、これはある種のコンパイラの最適化を示していますか?

4

2 に答える 2

10

setWithArray は基本的なアドレス比較を行っているだけだと思います

それは正しくありません。NSSet は、追加されたオブジェクトに対して メソッド-isEqual:とメソッドを使用します。-hashそれらが Person またはそのスーパークラスでどのように実装されているかによって異なります。

その場合[person1 isEqual:person2]、セットには 1 つのオブジェクトが含まれていると予想されます。そうでない場合、セットには 2 つのオブジェクトが含まれている必要があります。

私の推測では、 Person はメソッドとメソッドのルールに従っていません。ほとんどの場合、2 つのオブジェクトは等しいですが、それらのハッシュは本来あるべきように等しくありません。(幸運に恵まれている 10 ~ 20% の時間を除いて。)-isEqual:-hash

オブジェクトが論理的に同じである場合、これはある種のコンパイラの最適化を示していますか?

いいえ、2 つのオブジェクトを 1 つにマージするコンパイラの最適化はありません。

于 2012-02-20T02:00:15.790 に答える
3

hashほとんどの場合、 for を実装していないためPerson、同じPersonオブジェクトが 2 つの異なるバケットにハッシュされることがあります。

于 2012-02-20T01:51:04.873 に答える