【发布时间】:2014-09-17 04:55:04
【问题描述】:
我有两个 NSString 对象。
NSString *a = @"ABC";
NSString *b;
谁能告诉我以下两行的区别
1) b = a;
2)b = [a copy];
【问题讨论】:
标签: objective-c memory-management copy deep-copy
我有两个 NSString 对象。
NSString *a = @"ABC";
NSString *b;
谁能告诉我以下两行的区别
1) b = a;
2)b = [a copy];
【问题讨论】:
标签: objective-c memory-management copy deep-copy
使用文字 NSString,copy 只返回相同的实例,因此这两行具有相同的效果,例如,b 是指向相同 NSString 的指针,如果您使用 NSLog(@"%p, %p", a, b),它们将打印相同的内容。
这不适用于其他类型的字符串,例如可变字符串或属性字符串。
【讨论】:
让我们找出答案!
正如迈克尔指出的那样,这里有一个复杂的问题。 NSStrings(在其他不可变类中)有一些优化可以掩盖这些语句中的差异。让我们先从一个可变类开始,以便更好地了解发生了什么,我们将使用 NSMutableString 代替。
首先我们将定义一些变量:
NSMutableString *stringVar = [[NSMutableString alloc] initWithString:@"abcdefg"];
NSMutableString *assignedVar = stringVar;
NSMutableString *copiedVar = [stringVar copy];
使用调试器,我们可以检查它们(您可以改用NSLog):
(lldb) p stringVar
(NSMutableString *) $0 = 0x0a477350 @"abcdefg"
(lldb) p assignedVar
(NSMutableString *) $1 = 0x0a477350 @"abcdefg"
(lldb) p copiedVar
(NSMutableString *) $2 = 0x0a478980 @"abcdefg"
这里的输出告诉我们变量的类型 (NSMutableString *),它指向的内存地址为十六进制值 (0x0a477350),以及在该地址找到的对象 (@"abcdefg")。
现在我们可以看到,当我们将一个变量分配给另一个变量 (assignedVar = stringVar) 时,我们将它们都设置为指向内存中的同一个对象,但是当我们调用 copy 时,我们会在一个新位置创建一个新对象,其中包含相同的数据。如果我们改变我们的字符串并再次打印这些变量,这将变得更加明显。
[stringVar appendString:@"hijk"];
(lldb) p stringVar
(NSMutableString *) $3 = 0x0a477350 @"abcdefghijk"
(lldb) p assignedVar
(NSMutableString *) $4 = 0x0a477350 @"abcdefghijk"
(lldb) p copiedVar
(NSMutableString *) $5 = 0x0a478980 @"abcdefg"
现在让我们回到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"
这里发生了什么?当我们使用不可变对象时,它们的内容无法改变,这意味着copy 不是一个有意义的操作。没有理由创建一个永远不会改变的对象的副本。编译器可以识别这一点,因此不会费心创建需要时间来实例化和使用额外内存的重复副本。这对我们来说很方便,但这确实意味着我们可以编写对可变数据不起作用但在我们拥有不可变对象时“起作用”的语句。
例如,我们应该使用-isEqualToString: 来比较字符串,但有时== “有效”,即使它实际上并没有执行我们预期的检查。看看你能不能弄清楚这里发生了什么:
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
【讨论】: