Reputation: 9
I have two NSString
objects.
NSString *a = @"ABC";
NSString *b;
Can someone please tell me the difference between the following two lines
1) b = a;
2) b = [a copy];
Upvotes: 0
Views: 62
Reputation: 17958
Let's find out!
There's a complication here as Michael pointed out. NSString
s (among other immutable classes) have some optimizations which can obscure the differences in these statements. Let's start with a mutable class first so we can better see what's going on, we'll use NSMutableString
instead.
First we'll define some variables:
NSMutableString *stringVar = [[NSMutableString alloc] initWithString:@"abcdefg"];
NSMutableString *assignedVar = stringVar;
NSMutableString *copiedVar = [stringVar copy];
Using the debugger we can inspect them (you could use NSLog
instead):
(lldb) p stringVar
(NSMutableString *) $0 = 0x0a477350 @"abcdefg"
(lldb) p assignedVar
(NSMutableString *) $1 = 0x0a477350 @"abcdefg"
(lldb) p copiedVar
(NSMutableString *) $2 = 0x0a478980 @"abcdefg"
The output here is telling us the type of the variable (NSMutableString *
), the memory address it points to as a hex value (0x0a477350
), and the object found at that address (@"abcdefg"
).
Now we can see that when we assign one variable to another (assignedVar = stringVar
) we are settings them both to point to the same object in memory but when we call copy
we create a new object at a new location containing the same data. This becomes more obvious if we mutate our string and print these variables again.
[stringVar appendString:@"hijk"];
(lldb) p stringVar
(NSMutableString *) $3 = 0x0a477350 @"abcdefghijk"
(lldb) p assignedVar
(NSMutableString *) $4 = 0x0a477350 @"abcdefghijk"
(lldb) p copiedVar
(NSMutableString *) $5 = 0x0a478980 @"abcdefg"
Now let's go back to NSString
:
NSString *stringVar = @"abc";
NSString *assignedVar = stringVar;
NSString *copiedVar = [stringVar copy];
(lldb) p stringVar
(NSString *) $0 = 0x0a73e418 @"abc"
(lldb) p assignedVar
(NSString *) $1 = 0x0a73e418 @"abc"
(lldb) p copiedVar
(NSString *) $2 = 0x0a73e418 @"abc"
What happened here? When we're working with immutable objects there's no way their contents can change which means that copy
isn't a meaningful operation. There's no reason to create a copy of an object which can never change. The compiler can recognize this and so doesn't bother creating a duplicate copy which would require time to instantiate and use additional memory. That's handy for us but it does mean we can write statements which wouldn't work as intended with mutable data but "work" when we have immutable objects.
For example, we should use -isEqualToString:
to compare strings but sometimes ==
"works" even though it is not actually performing the check we had intended. See if you can figure out what's going on here:
NSString *string1 = @"a";
NSString *string2 = @"a";
NSMutableString *mutableString1 = [[NSMutableString alloc] initWithString:@"a"];
NSMutableString *mutableString2 = [[NSMutableString alloc] initWithString:@"a"];
(lldb) p string1
(NSString *) $0 = 0x0aa3d458 @"a"
(lldb) p string2
(NSString *) $1 = 0x0aa3d458 @"a"
(lldb) p (BOOL)[string1 isEqualToString:string2]
(BOOL) $2 = YES
(lldb) p (BOOL)(string1 == string2)
(BOOL) $3 = YES
(lldb) p mutableString1
(NSMutableString *) $4 = 0x0a330d40 @"a"
(lldb) p mutableString2
(NSMutableString *) $5 = 0x107087d0 @"a"
(lldb) p (BOOL)[mutableString1 isEqualToString:mutableString2]
(BOOL) $6 = YES
(lldb) p (BOOL)(mutableString1 == mutableString2)
(BOOL) $7 = NO
Upvotes: 0
Reputation: 18717
With a literal NSString, copy simply returns the same instance, so those two lines have the same effect, e.g., b is a pointer to the same NSString, and if you did NSLog(@"%p, %p", a, b)
, they would print the same.
This would not be true for other types of strings, such as a mutable or attributed string.
Upvotes: 2