2010-09-13 4 views
78

Sia i seguenti confronti restituiscono true:confronto NSString intesa

1)

@"foo" == @"foo"; 

2)

NSString *myString1 = @"foo"; 
NSString *myString2 = @"foo"; 
myString1 == myString2; 

Tuttavia, ci sono sicuramente momenti in cui due NSString s non può essere paragonata con l'operatore di uguaglianza e invece è richiesto [myString1 isEqualToString:myString2]. Qualcuno può fare luce su questo?

risposta

155

Il motivo per cui == funziona dipende dal confronto tra i puntatori. Quando si definisce una costante NSString utilizzando @"", il compilatore unifica il riferimento. Quando le stesse costanti sono definite in altri punti del codice, puntano tutte alla stessa posizione effettiva nella memoria.

Quando si confrontano NSString casi, si dovrebbe utilizzare il metodo isEqualToString::

NSString *myString1 = @"foo"; 
NSString *myString2 = @"foo"; 
NSString *myString3 = [[NSString alloc] initWithString:@"foo"]; 
NSLog(@"%d", (myString2 == myString3)) //0 
NSLog(@"%d", (myString1 == myString2)); //1 
NSLog(@"%d", [myString1 isEqualToString:myString2]); //1 
NSLog(@"%d", [myString1 isEqualToString:myString3]); //1 
[myString3 release]; 
+6

La maggior parte dei compilatori renderà anche 'myString3' un puntatore alla costante' "foo" 'come ottimizzazione, quindi, in generale, tutte e tre queste variabili punteranno alla stessa posizione di memoria. Questo vale sia per gcc che per clang (con opzioni predefinite). Prova a compilare questo: http://gist.github.com/578568 – mipadi

+0

e quindi come posso fare una variabile NSString comportarsi esattamente come @ "..."? la ragione per cui chiedo è b/c nel mio codice in questo momento la costante @ ".." funziona ma si blocca non appena la sostituisco con una variabile NSString .. vedi [qui] (http://stackoverflow.com/questions/14462951/ios-sqlite3-statement-coalesce-causare-memory-problems) – abbood

+2

+1, Solo per aggiungere: 'isEqual:' fa infatti un confronto tra stringhe complete e restituisce lo stesso risultato di 'isEqualToString' perché il _NSObject Protocol Reference_ e _NSString Class Reference_ specificano esplicitamente (rispettivamente): "Se due oggetti sono uguali (per' -isEqual: ') devono avere lo stesso valore di hash" AND "Se due oggetti stringa sono uguali (come determinato dal metodo isEqualToString:) , devono avere lo stesso valore hash. " – Ephemera

6

Nelle stringhe di cacao vengono confrontati utilizzando il metodo isEqualToString: di NSString.

Il confronto del puntatore funziona nel tuo caso perché il compilatore è abbastanza delicato da unire i due valori letterali stringa per puntare a un oggetto. Non c'è alcuna garanzia che due stringhe identiche condividano un'istanza NSString.

+0

Avete qualche riferimento ufficiale a questo?"Non c'è alcuna garanzia che due stringhe identiche condividano un'istanza NSString." –

+0

@ user3055655 Non ho bisogno di un riferimento: puoi facilmente scrivere codice che crea due distinte istanze di 'NSString' con contenuto identico:' [NSMutableString string]! = [NSMutableString string] ' –

+0

@ user3055655 Se intendi che il mio reclamo è non è vero per i letterali stringa: prova letterali da due pacchetti (come un'app e il relativo bundle di test). –

13

L'operatore di uguaglianza == confronta solo indirizzi di puntatore. Quando crei due stringhe identiche usando la sintassi letterale @"", il compilatore rileverà che sono uguali e memorizza i dati una sola volta. Quindi, i due puntatori indicano la stessa posizione. Tuttavia, stringhe create con altri mezzi possono contenere dati identici, ma possono essere archiviate in posizioni di memoria differenti. Pertanto, è necessario sempre utilizzare isEqual: quando si confrontano le stringhe.

Nota che isEqual: e isEqualToString: restituiscono sempre lo stesso valore, ma isEqualToString: è più veloce.

+2

Si noti inoltre che 'isEqualToString': causerà un'eccezione se il parametro passato ad esso è' nil'. Quindi, se c'è una possibilità che stai comparando con una stringa nil, dovresti prima fare un controllo nullo o usare 'isEqual:' –

10

== confronta le posizioni in memoria. ptr == ptr2 se entrambi puntano alla stessa posizione di memoria. Questo succede a lavorare con costanti di stringa perché il compilatore capita di usare una stringa effettiva per costanti di stringa identiche. Lo non funzionerà con se si hanno variabili con lo stesso contenuto, perché puntano a posizioni di memoria diverse; utilizzare isEqualToString in questo caso.

+0

Puoi illuminare con un esempio di cosa intendi "non funzionerà se hai variabili con lo stesso contenuto" –

3

Un esempio che dimostra come il confronto indirizzo di un surrogato per confronto di stringhe si romperà:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSString *s1 = @"foo"; 
    NSString *s2 = @"foo"; 
    NSString *s3 = [[[NSString alloc] initWithString:@"foo"] autorelease]; 
    NSMutableString *s4 = [NSMutableString stringWithString:@"foobar"]; 
    [s4 replaceOccurrencesOfString:@"bar" 
         withString:@"" 
          options:NSLiteralSearch 
          range:NSMakeRange(0, [s4 length])]; 

    NSLog(@"s1 = %p\n", s1); 
    NSLog(@"s2 = %p\n", s2); 
    NSLog(@"s3 = %p\n", s3); 
    NSLog(@"s4 = %p\n", s4); // distinct from s1 

    NSLog(@"%i", [s1 isEqualToString:s4]); // 1 

    [pool release]; 
0

Partenza questo esempio:

NSString *myString1 = @"foo"; 
NSMutableString *myString2 = [[NSMutableString stringWithString:@"fo"] stringByAppendingString: @"o"]; 

NSLog(@"isEquality: %@", ([myString1 isEqual:myString2][email protected]"+":@"-")); //YES 
NSLog(@"isEqualToStringity: %@", ([myString1 isEqualToString:myString2][email protected]"+":@"-")); //YES 
NSLog(@"==ity: %@", ((myString1 == myString2)[email protected]"+":@"-")); // NO 

Così, il compilatore è probabile che utilizzare il metodo isEqualToString per elaborare isEquals per i puntatori di NSString e di dereferenziazione, anche se non era necessario. E i puntatori sono diversi, come vedi.

-1
NSString *str1=[NSString stringWithFormat:@"hello1"]; 
    NSString *str2=[NSString stringWithFormat:@"hello1"]; 
    NSString *str3 = [[NSString alloc] initWithString:@"hello1"]; 




// == compares the pointer but in our example we are taking same string value to different object using @ so it will point to same address so output will be TRUE condition 
    if (str1==str2) { 
     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 
    } 


    // == compares the pointer but in our example we are taking same string value to different object but we have allocated different string so both object will pount to different address so output will be FALSE condition 
    if (str1==str3) { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 


    // compare:= compares the values of objects so output will be TRUE condition 
    if ([str1 compare:str3]== NSOrderedSame) { 
     NSLog(@"Both String are equal"); 

    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 


    // isEqual compares the values of objects so output will be TRUE condition 

    if ([str1 isEqual:str2]) { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 

    // isEqual compares the values of objects so output will be TRUE condition 

    if ([str1 isEqual:str3]) { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 


    // isEqualToString compares the values of objects so output will be TRUE condition 
    if ([str1 isEqualToString:str2]) { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 


    // isEqualToString compares the values of objects so output will be TRUE condition 
    if ([str1 isEqualToString:str3]) { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    } 

    // == compares the pointers since we have initialized the same value to first object so the pointer be be same for same value so output will be TRUE condition 
    if ([email protected]"hello1") { 

     NSLog(@"Both String are equal"); 
    } 
    else{ 
     NSLog(@"Both String not are equal"); 

    }