0

Suppose I have a NSString* str1 and NSMutableString* str2, and I make str2 the mutable copy of str1. And I called the following method:

-(void)someMethod {
    NSString *str1;
    NSMutableString *str2;
    str1 = @"OK";
    str2 = [str1 mutableCopy];

    if ([str2 isEqual:str1]) {
        NSLog(@"Same!");
    }
    else {
        NSLog(@"Not exactly!");
    }

    NSLog(@"%@", [[str1 class] description]);
    NSLog(@"%@", [[str2 class] description]);
}

Console output:

2014-01-07 14:03:16.291 LearnFoundation[3739:303] Same!
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFConstantString
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFString

So here comes the confusion, according to the documentation of isEqual in NSString, it returns a Boolean value that indicates whether the receiver and a given object are equal. So why the mutable copy is said to be the same as the original immutable one?
Thanks in advance!

John Wu
  • 1,015
  • 1
  • 12
  • 21
  • 3
    `isEqual` compares the characters, not the pointer references, so they will be equal until you mutate `str2`. See also http://stackoverflow.com/questions/3703554/understanding-nsstring-comparison – StuartLC Jan 07 '14 at 06:12

3 Answers3

1

isEqual compares the contents of the two strings, not their types or identities. The contents are equal so it evaluates true.

To compare types, try:

if([str1 isKindOfClass:[str2 class]])
{ 
   NSLog(@"same");
}else{
   NSLog(@"different");
}

You should see "different" get logged.

bergy
  • 1,395
  • 9
  • 11
  • 1
    This may be tricky with strings, since NSCFString (a private subclass of NSString) can be used for both mutable and immutable strings. – Catfish_Man Jan 07 '14 at 06:20
1

There are (at least) three separate concepts that can all be thought of as "equality":

  1. "identity" (am I the same object as that other object?)
  2. "equality" (am I exactly identical to this other object?)
  3. "value equality" (do I have the same value as this other object?)

For ObjC objects you test for equal identities with ==, but equivalent values with isEqual:. There's no one-stop shop method for testing exact equality; it turns out to not be very useful, in general.

In Javascript (for comparison's sake), you test for equal identities with === and equivalent values with ==. There is similarly no direct way to test for exact equality.

For pass-by-value types like int and float, there's no such thing as identity, since you can't pass a particular instance around. However, if you squint a bit, you can think of this as being a similar case of different types with the same value:

int x = 5;
short y = 5;
if (x == y) {
    ...
}

Though in this case it's not a subtype relationship.

Catfish_Man
  • 41,261
  • 11
  • 67
  • 84
0

They're equal as strings, but are distinct objects with distinct addresses. Thus, isEqual returns YES but a comparison with == would evaluate to NO.

Ken
  • 30,811
  • 34
  • 116
  • 155