Bagaimana Anda menimpa dengan benar isEqual:
di Objective-C? "Tangkapan" tampaknya bahwa jika dua objek sama (seperti yang ditentukan oleh isEqual:
metode), mereka harus memiliki nilai hash yang sama.
Bagian Introspeksi dari Panduan Dasar-Dasar Kakao memang memiliki contoh tentang cara menimpa isEqual:
, disalin sebagai berikut, untuk kelas bernama MyWidget
:
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToWidget:other];
}
- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
if (self == aWidget)
return YES;
if (![(id)[self name] isEqual:[aWidget name]])
return NO;
if (![[self data] isEqualToData:[aWidget data]])
return NO;
return YES;
}
Ini memeriksa kesetaraan pointer, kemudian kelas kesetaraan, dan akhirnya membandingkan objek menggunakan isEqualToWidget:
, yang hanya memeriksa name
dan data
properti. Apa yang tidak ditunjukkan contoh ini adalah cara menimpa hash
.
Anggaplah ada properti lain yang tidak memengaruhi kesetaraan, katakanlah age
. Bukankah seharusnya hash
metode diganti sehingga hanya name
dan data
mempengaruhi hash? Dan jika demikian, bagaimana Anda akan melakukannya? Cukup tambahkan hash dari name
dan data
? Sebagai contoh:
- (NSUInteger)hash {
NSUInteger hash = 0;
hash += [[self name] hash];
hash += [[self data] hash];
return hash;
}
Apakah itu cukup? Apakah ada teknik yang lebih baik? Bagaimana jika Anda memiliki primitif, seperti int
? Konversikan mereka ke NSNumber
untuk mendapatkan hash mereka? Atau struct suka NSRect
?
( Brain fart : Awalnya menulis "bitwise OR" bersama dengan mereka |=
. Dimaksudkan menambahkan.)
if (![other isKindOfClass:[self class]])
- Ini secara teknis berarti kesetaraan tidak akan bersifat komutatif. Yaitu A = B tidak berarti B = A (misalnya jika satu adalah subkelas yang lain)