1

Possible Duplicate:
Understanding NSString comparison in Objective-C

Was just reading up about equality vs identity and I realized that I've been using some equal signs when comparing strings in my objc code. The weird thing is that it actually works from times to times and I was wondering why.

http://www.karlkraft.com/index.php/2008/01/07/equality-vs-identity/

I have two pieces of code, one work and one doesn't.

WORKING. Here I have a object called 'Category' which has a NSString property called 'name'.

@property (nonatomic, retain) NSString *name;

I then have a function where I pass in a 'Catergory' pointer and when I use the equal sign here, it works perfectly.

 -(void)addCategoryToStorage:(Category*)newcategory {
      if(newcategory.name != @"All") {  // this works

NON WORKING. Here I use the output from a NSFileManager call;

NSArray *dirContent = [self.fileManager 
                       contentsOfDirectoryAtPath:@"MyFiles"
                       error:nil];

I then try to compare on of the NSStrings in the array:

for(int i = 0; i < [dirContent count]; i++) { 
    if([dirContent objectAtIndex:i] == @"MyFile") // This will never be True

So my questions is, what would be the reason why these two NSString pointers would work so differently? I know I shouldn't use "==" but at the moment, but I'm just so curious why it works sometimes.

I noticed some difference between them debugging. In the first case, the "newcategory"s "name" said (__NSCFConstantString*) and had the value visible. For some reason, the "dirContent" arrays contains two (__NSString*) objects where the values aren't visible.

This raises another question. What makes the NSString in the first case to become a constant? It seems to have something to with how it's created when I pass it to the function. When I allocate a new object with a NSString property that I then pass in to a function, the function sees it a constant(The NSString property of the object). But when the object is stored in a list and I grab it by passing [array objectAtIndex:index] into a function, the functions doesn't get it as a constant (the NSString property of the object that is).

Thanks!

Community
  • 1
  • 1
chikuba
  • 4,229
  • 6
  • 43
  • 75

3 Answers3

5

It may work, when the pointers point to the same object.

If you have a string literal in your code, it is actually a statically allocated object of type NSString. At any point in your code, if you would reference this string value, you are actually using the same pointer. (A pointer is basically a memory address)

If you have the string literal @"abc" at more than one point in your code, the compiler only puts in one instance, and uses a pointer to this single instance.

This explains why @"abc" == @"abc".

Taking your example:

if(newcategory.name != @"All")

will only work if at some point in your code you did:

newcategory.name = @"All";

And will not work if you would do:

newcategory.name = [NSString stringWithFormat:@"%c%c%c",'A','l','l'];

because in that last case you explicitly allocate a new string.

edit just tested, this example was flawed:

newcategory.name = [NSString stringWithString:@"All"];

because this is optimized away so you will have the same pointer to @"All"

mvds
  • 45,755
  • 8
  • 102
  • 111
  • 3
    The technical term is *string interning*. – Georg Fritzsche Feb 06 '12 at 00:16
  • 1
    So the compiler will not make any difference between [NSString stringWithString:@"All"] and @"All"? – chikuba Feb 06 '12 at 00:29
  • And what about the way the compiler makes the string into a constant in some cases? I have two functions where I provide it with a Category pointer and sometimes the NSString is a constant. – chikuba Feb 06 '12 at 00:32
  • 1
    @chikuba: String literals will be constant string instances (already known at compile time etc.), while other string instances will be dynamically created. As for `+stringWithString:`, it doesn't have to actually copy/clone if the argument is a constant string. There are no guarantees for string interning or those copy optimizations etc. though. – Georg Fritzsche Feb 06 '12 at 00:37
  • @chikuba: I'm not sure about these things. You are treading into undocumented areas (afaik), which means that behavior might depend on compiler/runtime versions. The general rule is that you should only use `==` for pointer comparisons if you are in fact testing if pointers reference the same object. Normally, you just shouldn't do this. Incidentally, this may be useful. (e.g. `NSManagedObject` instances obtained from Core Data are guaranteed to occur once per object in the data store, therefore it is safe to compare pointers instead of calling `-isEqual:`) – mvds Feb 06 '12 at 00:39
0

When you compare with == you aren't comparing the strings themselves, you are comparing the values of the pointers to the strings. When you declare string literals in your code they are stored in the data segment of your executable. If more than one string variable is pointing to the same string literal, they may be pointing to the same memory location.

When you load the string from a file, the pointers cannot be equal since they couldn't have possibly come from the data segment of the executable.

For example, the two string literals asdf will often only be stored once in the executable, thus the values of the pointers will be equal. This is an optimization performed by the compiler though and will not always work.

NSString* someVariable = @"asdf";

if(someVariable == @"asdf")
   NSLog(@"They are equal!");
DHamrick
  • 8,338
  • 9
  • 45
  • 62
0

NString ALWAYS works with the "==" sign, if you want to compare two pointers to see if they reference the EXACT SAME object.

And short literals are generally pooled in such a way that likely @"ABC" == @"ABC", even if one of those literals is in a different class.

But don't count on it.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • I'm aware of that. Atm I would like to know what the biggest difference is between my two NSStrings and also why the compiler turns my object property strings to const in some cases. – chikuba Feb 06 '12 at 00:25
  • 1
    There are some mysteries that are better left unknown. ;) (Actually, I don't understand all the details, but in Objective-C an object like an NSString can be one of several different underlying classes, depending on exactly how it was created. Doesn't really matter, though, since an NSString is *always* constant, and it will respond correctly to all the appropriate methods/selectors regardless of its underlying class.) – Hot Licks Feb 06 '12 at 01:35