2015-12-05 13 views
13

Nella mia app, per sbaglio ho usato "==" quando si confrontano due NSNumber oggetti in questo modo:iOS - Perché funziona quando confronto due NSNumbers con "=="?

NSNumber *number1; 
NSNumber *number2; 

Più tardi, dopo int valori questi oggetti sono stati fissati, l'ho fatto per sbaglio questo:

if (number1 == number2) { 
    NSLog(@"THEY'RE EQUAL"); 
} 

E, in modo confuso, ha funzionato! Avrei giurato mi è stato insegnato a fare in questo modo:

if (number1.intValue == number2.intValue) { 
    NSLog(@"THEY'RE EQUAL"); 
} 

Come ha fatto con "==" tra i due NSNumber oggetti di lavoro, e perché? Ciò significa che va bene confrontarli in questo modo, o è stato solo un caso e di solito non è garantito che funzioni ogni volta? E 'veramente mi :(

+0

in realtà, il "intValue" fallirà in molti casi. Se entrambi gli NSNumbers contengono numeri interi grandi o numeri di virgola mobile diversi ma vicini, ad esempio. – gnasher729

risposta

6

confuso che è forse un colpo di fortuna

Da NSHipster:.

due oggetti possono essere uguali o equivalenti a uno con l'altro, se condividono un insieme comune di proprietà osservabili. Tuttavia, questi due oggetti possono ancora essere pensati per essere distinti, ognuno con la propria identità.In programmazione, l'identità di un oggetto è legata al suo indirizzo di memoria

E 'possibile che la tua dichiarazione evalua ted to YES perché number1 e number2 puntavano allo stesso oggetto. Questo non funzionerebbe se avessero lo stesso valore ma fossero due oggetti diversi.

La ragione ovvia NSNumber variabili sarebbero puntare alla stessa sarebbe che si è assegnato in modo esplicito l'uno all'altro, in questo modo:

number1 = number2; 

Ma c'è un'altra cosa . Da this answer:

Ciò è probabile sia un'ottimizzazione del compilatore o un dettaglio di implementazione: come NSNumber è immutabile non c'è bisogno di loro siano istanze separate. probabilmente un'ottimizzazione dell'implementazione a pensarci. Probabilmente numberWithInt restituisce un singleton quando viene chiamato successivamente con lo stesso numero intero.

Ma in ogni modo, la sua più sicura da usare isEqualToNumber:, come non si può dire ciò che gli altri "cose" sono in agguato nelle profondità di codice che può o non può causare a valutare YES

Da RyPress :

Mentre è possibile confrontare direttamente i puntatori NSNumber, il metodo isEqualToNumber: è un modo molto più robusto per verificare l'uguaglianza. Garantisce che due valori saranno uguali, anche se sono memorizzati in oggetti diversi.

+0

Ho letto qui (http://www.toptal.com/ios/interview-questions) (solo control-f search "==" e troverai la domanda e la risposta) che il compilatore iOS è ottimizzato per impostare il stesso indirizzo in memoria per due 'NSStrings' che condividono lo stesso valore. Forse lo stesso funziona per 'NSNumber'? – Rafi

+0

Sì, ma non penso che valga per "NSNumber". Controllerò e torno da te. – ShahiM

+0

Hmmm, quindi se ho oggetti "Amico" in cui l'attributo "identificatore" di "NSNumber" di ognuno sarà sempre assegnato e referenziato come "intValue", posso sempre farla franca con il confronto usando "=="? – Rafi

2

Ci due concetti di uguaglianza sul lavoro qui:

  • identità Oggetto: Confrontando che due puntatori puntano agli stessi oggetti
  • uguaglianza Valore: Che il contenuto di due oggetti sono uguali.

In questo caso, si desidera l'uguaglianza di valore. Nel codice si dichiara due puntatori a NSNumber oggetti:

NSNumber *number1; 
NSNumber *number2; 

ma a nessuna assegnazione punto dimostrazione di un valore per loro. Ciò significa che il contenuto dei puntatori può essere qualsiasi cosa, e per puro caso si hanno due puntatori che puntano alle posizioni di memoria (non necessariamente le stesse) dove lo (number1.intValue == number2.intValue) risulta essere vero.

È possibile aspettarsi che il comportamento cambi in modo instabile, ad esempio non appena si aggiunge altro codice.

+0

Si noti che sotto ARC, i valori del puntatore di oggetto non inizializzato ** sono ** ben definiti: sono 'nil'. –

2

Ovviamente è possibile confrontare due NSNumber * con ==. Questo ti dirà se i puntatori sono uguali. Naturalmente se i puntatori sono uguali, i valori devono essere uguali. I valori possono essere gli stessi senza che i puntatori siano uguali.

Ora è necessario essere consapevoli del fatto che MaxOS X e iOS eseguono alcune ottimizzazioni significative per risparmiare spazio, specialmente nel codice a 64 bit. Molti NSNumbers che rappresentano lo stesso valore intero saranno in realtà lo stesso puntatore.

NSNumber* value1 = [[NSNumber alloc] initWithInteger:1]; 
NSNumber* value2 = [[NSNumber alloc] initWithInteger:1]; 

Questi saranno gli stessi puntatori. A 64 bit, molti altri saranno gli stessi indicatori. Esistono solo due oggetti NSNumber con valori booleani. C'è sempre un solo oggetto NSArray vuoto e solo un oggetto [NSNull null].

Non lasciare che ti cali in ipotesi sbagliate. Se vuoi vedere se due NSNumbers hanno lo stesso valore, usa isEqualToNumber: puoi dire "if (number1 == number2 || [number1 isEqualToNumber: number2])"; va bene (non ho controllato se ho capito bene i nomi).

10

Non è un colpo di fortuna. È dovuto alla funzionalità dei puntatori codificati del runtime Objective-C mentre si utilizza una CPU ARM64.

In Mac OS X 10.7, Apple ha introdotto puntatori con tag. Puntatori con tag consentono ad alcune classi con piccole quantità di dati per istanza di essere memorizzate interamente all'interno del puntatore. Questo può eliminare la necessità di allocazioni di memoria per molti usi di classi come NSNumber e può dare un buon incremento delle prestazioni. [...] su ARM64, il runtime Objective-C include puntatori con tag, con tutti gli stessi benefici che hanno portato al Mac

Source

Problemi correlati