Preet
Preet

Reputation: 9

Copy in Objective C

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

Answers (2)

Jonah
Jonah

Reputation: 17958

Let's find out!

There's a complication here as Michael pointed out. NSStrings (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

Michael Chinen
Michael Chinen

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

Related Questions