2009-08-06 5 views
26

Ho una classe modello di database che è un NSObject. Ho un set di questi oggetti in un NSMutableArray. Io uso indexOfObject: per trovare una corrispondenza. Il problema è la modifica dell'indirizzo di memoria dell'oggetto modello. Quindi sto ignorando il metodo hash per restituire l'ID della riga del modello. Questo tuttavia non lo aggiusta. Devo anche eseguire l'override del metodo isEqual: per confrontare il valore del metodo hash.Che cos'è NSObject isEqual: e funzione di hash predefinita?

Cosa utilizza il metodo isEqual: per determinare l'uguaglianza per impostazione predefinita?

Suppongo che utilizzi l'indirizzo di memoria. Dopo aver letto la documentazione isEqual: ho pensato di utilizzare il valore del metodo hash. Ovviamente, questo non è il caso in quanto il mio tentativo di ignorare quel valore non ha risolto il mio problema iniziale.

+0

Ci sono alcune risposte speculative qui. Qualcuno può fornire una documentazione vera e propria che il valore predefinito è Equals usa indirizzo> Non sto suggerendo che non lo fa, vorrei solo sentirlo dalla bocca del cavallo. – DougW

+0

@DougW Ho condiviso i tuoi sentimenti su questo, quindi ho rintracciato un riferimento ufficiale e l'ho modificato nella risposta accettata. –

+0

Stai leggendo i documenti per il protocollo NSObject, non la classe NSObject. Il protocollo definisce che cosa dovrebbero fare i metodi, la classe non riesce a definire cosa effettivamente fa. È sempre più sicuro scavalcare equals e hash per lavorare come vuoi che funzionino. –

risposta

26

Come hai giustamente intuito, il comportamento NSObject predefinito isEqual: sta confrontando l'indirizzo di memoria dell'oggetto. Stranamente, questo non è attualmente documentato nel NSObject Class Reference, ma è documentato nella documentazione Introspection, in cui si afferma:

L'implementazione predefinita NSObject di isEqual: controlla semplicemente per l'uguaglianza puntatore.

Naturalmente, come si è certamente a conoscenza, sottoclassi di NSObject possono ignorare isEqual: a comportarsi in modo diverso. Ad esempio, il metodo NSString di isEqual:, quando viene passato un altro NSString, controlla prima l'indirizzo e quindi verifica la corrispondenza letterale esatta tra le stringhe.

+0

Un riferimento per questo sarebbe bello. –

+1

... quindi ne ho aggiunto uno. Stranamente, il riferimento alla classe 'NSObject' non ha nemmeno una voce per' isEqual: ', per non parlare del suo comportamento ovunque, che sembra un'omissione clamorosa. Tuttavia, sono stato in grado di rintracciare un riferimento ufficiale in qualche pagina oscura nella sezione "concettuale" dei documenti. –

+0

La documentazione di Apple è piena di casi in cui i metodi di protocollo non sono documentati nella documentazione di classe. (Per non parlare dei metodi della superclasse.) Spesso devi cercare sotto molte pietre per trovare la documentazione per un determinato metodo. –

4

Suppongo che NSObjectisEquals utilizzi l'operatore == e hash utilizzi l'indirizzo di memoria.

isEquals metodo non dovrebbe mai utilizzare hash come un test assoluto per l'uguaglianza. È garantito che due oggetti con lo stesso valore , se si cercano oggetti sufficienti (basta creare più di 2^32 oggetti diversi, e almeno due di essi avranno lo stesso hash).

In altre parole, hash richiede la seguente specifica: se due oggetti sono uguali, il loro hash deve essere uguale; tuttavia, se i valori di due oggetti "hash sono uguali, non sono necessariamente uguali.

Come suggerimento, è sempre necessario eseguire l'override di isEquals e hashCode insieme.

+21

"Suppongo che sia una cosa sfortunata iniziare una risposta con ... –

8

La risposta sull'implementazione predefinita di isEqual: è completa. Quindi aggiungo la mia nota sull'implementazione predefinita di hash. Eccolo:

-(unsigned)hash {return (unsigned)self;} 

cioè è proprio lo stesso valore del puntatore che viene utilizzato in isEqual:.Ecco come è possibile controllare questo fuori:

NSObject *obj = [[NSObject alloc] init]; 
NSLog(@"obj: %@",obj); 
NSLog(@"hash: %x",obj.hash); 

Il risultato sarà qualcosa di simile:

obj: <NSObject: 0x16d44010> 
hash: 16d44010 

migliori saluti.

BTW in iOS 8 hash è diventato una proprietà non un metodo, ma è lì.