isEqual i hash van junts
No sé si us heu creat classes on implementeu el mètode "isEqual:". Si ho feu heu de saber que segurament també haureu d'implementar el mètode hash.
El mètode isEqual s'ha d'implementar si voleu utilitzar una classe dins d'un NSSet. Els NSSet contenen un conjunt d'objectes on no es repeteix cap objecte, és a dir, que si hi afegiu un objecte que ja hi és, no s'incrementa el nombre d'element. I la configuració la fa amb el mètode "isEqual:". També cal implementar-lo si utilitzeu arrays NSArray i voleu cercar objectes amb el mètode "containsObject:" o "indexOfObject:". Aquests mètodes també fan servir el mètode isEqual.
Bé, fins aquí no hi ha cap problema, i implementar el mètode "isEqual:" en principi tampoc, bàsicament només cal comparar la classe de l'objecte i els atributs que tenen.
Però el problema ve quan no implementeu el mètode "hash" i el que ve per defecte retorna valors diferents per objectes iguals "isEqual". Llavors les llistes no funcionaran.
03 octubre 2008 11:06
Posem-hi un exemple: Imagineu-vos que teniu una classe amb dos enters, quelcom així:
@class TwoInt : NSObject
{
unsigned int _int1;
unsigned int _int2;
}
Aquesta classe no té importància l'ordre dels enters, així que la comparació "isEqual:" primer ordenarà els enters i després els compararà. Més o menys així:
- (BOOL) isEqual:(id)tObj
{
// Comprovem que siguin de la mateixa classe
if ( ![tObj isKindOfClass:[self class]] )
return NO;
// Ordenem els valors
unsigned int myLowest = _int1 > _int2 ? _int2 : _int1;
unsigned int objLowest = [tObj int1] > [tObj int2] ? [tObj int2] : [tObj int1];
if ( myLowest != objLowest )
return NO;
unsigned int myGreatest = _int1 <= _int2 ? _int2 : _int1;
unsigned int obj Greatest = [tObj int1] <= [tObj int2] ? [tObj int2] : [tObj int1];
if ( myGreatest != Greatest )
return NO;
return YES;
}
Molt bé, si no hi ha cap error de transcripció, que ho he fet a ulls clucs, la comparació ja funciona, però ves per on, el has d'ambdós objectes és diferent, ja que si no recordo malament el "hash" per defecte es fa a partir del contingut de la memòria. És a dir, que te en compte l'ordre dels atributs.
Així que nosaltres hem de solucionar aquest problema i re-implementar el mètode per a que dos objectes iguals retornin hash iguals. Hi ha moltes maneres de fer-ho, podem agafar només un valor (sempre el mateix) com a hash o ordenar els objecte, o qualsevol altre mètode. Però és obligatori que objectes iguals retornin hash iguals. Tanmateix, no cal que objectes diferents retornin hash diferents, també poden ser iguals. Aquí teniu un parell d'exemple d'aquest mètode hash.
El primer exemple agafa el valor més petit i l'utilitza com a hash:
- (NSUInteger) hash
{
unsigned int myLowest = _int1 > _int2 ? _int2 : _int1;
return myLowest;
}
El segon exemple agafa els dos valors i en fa una operació que no té en compte l'ordre. Així ens assegurem que sempre retornarà el mateix valor.
- (NSUInteger) hash
{
return _int1 ^ _int2;
}
Penseu que el hash sempre ha de retornar un enter sense signe, així que si teniu cadenes de text, haureu de trobar una forma de trobar-hi un hash. La forma més senzilla és cridar el propi mètode "hash" del propi objecte. I fer-ne les operacions que calguin per a obtenir el vostre.
return [@"my attribute" hash];
03 octubre 2008 11:26
Hola, no entenc gaire el que vols dir, el hash no acabo d'entendre el que és.
En el meu cas, he utilizat isEqual: per comparar objectes, que no es el mateix que vols fer, però o volia comentar.
L'únic es que per que funcioni, es te que canviar el mètode description per que retorni la variable que vulguem, i pot ser un NSString o el que vulguem, i això es el que s'utilitza en la comparació.
05 octubre 2008 19:10
El hash és un número on les col·leccions d'objectes utilitzen com a índex. És a dir, que els objectes que hi fiquis a dins quedaran etiquetats en aquell número. Tots agrupats.
Quan vulguis cercar un element, el sistema primer calcularà el hash, llavors cercarà tots els objectes que hi ha en aquell índex i farà la comparació amb la funció "isEqual:". Així ha de fer moltes menys comparacions i és molt més ràpid.
Si per algun motiu, dos objectes que són iguals (com els de l'exemple) retornen hash diferents. No els compararà mai, perquè els cercarà en un hash diferent. Hi ha un gràfic aquí: http://en.wikipedia.org/wiki/Hash_table

Per cert, el mètode description només serveix per representar en forma de cadena un objecte que pots fer servir per imprimir-lo (per exemple).
05 octubre 2008 22:12
