2010-09-13 28 views
78

Les deux comparaisons suivantes évaluent true:comparaison Comprendre NSString

1)

@"foo" == @"foo"; 

2)

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

Cependant, il y a certainement des moments où deux NSString s ne peuvent pas être comparés à l'aide l'opérateur d'égalité et [myString1 isEqualToString:myString2] est requis à la place. Quelqu'un peut-il nous éclairer à ce sujet?

Répondre

155

La raison pour laquelle fonctionne == est due à la comparaison de pointeurs. Lorsque vous définissez une constante NSString en utilisant @"", le compilateur uniquifies la référence. Lorsque les mêmes constantes sont définies dans d'autres endroits de votre code, elles pointent toutes vers le même emplacement réel en mémoire.

Lorsque l'on compare NSString cas, vous devez utiliser la méthode 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 plupart des compilateurs font également de myString3 un pointeur vers la constante '" foo "' en guise d'optimisation, donc généralement, ces trois variables pointent vers le même emplacement mémoire. Cela est vrai pour gcc et clang (avec les options par défaut). Essayez de compiler ceci: http://gist.github.com/578568 – mipadi

+0

et comment puis-je faire une variable NSString se comporter exactement comme @ "..."? la raison pour laquelle je demande est b/c dans mon code maintenant la constante @ ".." fonctionne mais elle se bloque dès que je la remplace par une variable NSString .. voir [ici] (http://stackoverflow.com/questions/14462951/ios-sqlite3-instruction-coalesce-causant-des-problèmes) – abbood

+2

+1, Juste pour ajouter: 'isEqual:' fait en fait une comparaison de chaîne complète et retourne le même résultat que 'isEqualToString' parce que le protocole _NSObject Reference_ et _NSString Class Reference_ explicitement (respectivement): "Si deux objets sont égaux (par' -isEqual: ') ils doivent avoir la même valeur de hachage" AND "Si deux objets chaîne sont égaux (comme déterminé par la méthode isEqualToString:) , ils doivent avoir la même valeur de hachage. " – Ephemera

6

Dans Cocoa, les chaînes sont comparées à l'aide de la méthode isEqualToString: de NSString.

La comparaison de pointeurs fonctionne dans votre cas car le compilateur est assez doux pour fusionner les deux littéraux de chaîne pour pointer vers un objet. Il n'y a aucune garantie que deux chaînes identiques partagent une instance NSString.

+0

Avez-vous une référence officielle à ceci?"Il n'y a aucune garantie que deux chaînes identiques partagent une instance de NSString." –

+0

@ user3055655 Je n'ai pas besoin de référence: Vous pouvez facilement écrire du code qui crée deux instances 'NSString' distinctes avec un contenu identique:' [Chaîne NSMutableString]! = [Chaîne NSMutableString] ' –

+0

@ user3055655 Si vous voulez dire que ma demande est pas vrai pour les littéraux de chaîne: Essayez les littéraux de deux paquets (comme une application et son ensemble de tests). –

13

L'opérateur d'égalité == compare uniquement les adresses de pointeur. Lorsque vous créez deux chaînes identiques à l'aide de la syntaxe @"", le compilateur détectera qu'elles sont égales et ne stockera les données qu'une seule fois. Par conséquent, les deux pointeurs pointent vers le même emplacement. Cependant, les chaînes créées par d'autres moyens peuvent contenir des données identiques, mais être stockées à différents emplacements de mémoire. Par conséquent, vous devez toujours utiliser isEqual: lors de la comparaison des chaînes.

Notez que isEqual: et isEqualToString: retournent toujours la même valeur, mais isEqualToString: est plus rapide.

+2

Notez également que 'isEqualToString': provoquera une exception si le paramètre qui lui est passé est' nil'. Donc, s'il y a une chance que vous comparez à une chaîne nulle, vous devez d'abord faire une vérification nulle ou utiliser 'isEqual:' –

10

== compare les emplacements en mémoire. ptr == ptr2 s'ils pointent tous deux vers le même emplacement de mémoire. Cela arrive à travailler avec des constantes de chaîne parce que le compilateur arrive à utiliser une chaîne réelle pour des constantes de chaîne identiques. Il ne fonctionnera pas si vous avez des variables avec le même contenu, car ils pointeront vers des emplacements de mémoire différents; utiliser isEqualToString dans un tel cas.

+0

Pouvez-vous éclairer avec un exemple de ce que vous voulez dire "ça ne marchera pas si vous avez des variables Contenu" –

3

Un exemple montrant comment de comparaison de chaînes comparaison d'adresses comme substitut brisera:

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

Découvrez cet exemple:

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 

Ainsi, le compilateur est susceptible d'utiliser la méthode isEqualToString pour traiter isEquals pour les pointeurs de NSString et de déréférencement, bien que cela ne soit pas le cas. Et les pointeurs sont différents, comme vous le voyez.

-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"); 

    }