由NSString不变性引起的困惑

时间:2012-10-19 15:01:05

标签: objective-c cocoa nsstring

我是Objective-C新手。我正在努力应对可变性/不变性这两个概念。 我正在翻阅一本名为Programming in Objective-C 4th Edition的书。第15章讨论了NSString类,它被认为是不可变的。然后,本书提供的例子似乎与例如:

相矛盾
NSString *str1 = @"this is string A";
NSString *str2 = @"this is string B";

str2 = [str1 stringByAppendingString:str2];

NSString *res; 

res = [str1 substringToIndex:3];
res = [str1 substringFromIndex:5];
res = [[str1 substringFromIndex:8]substringToIndex:6];
res = [str1 substringWithRange:NSMakeRange(8, 6)];

所以尽管'res'是指向不可变对象的指针,但它的值已经改变了几次,所以如何将它称为immutable?我想我完全忽略了这一点。任何建议,感激不尽。

3 个答案:

答案 0 :(得分:4)

以下几行:

NSString *str2 = @"this is string B";
str2 = [str1 stringByAppendingString:str2];

您不会更改字符串“this be string B”的内容(存储在变量str2中),您可以将变量str2指向另一个字符串(由stringByAppendingString:方法生成的字符串)。

此处的差异与const char*char* const中的C完全相同。

  • NSString*const char*都表示指向其内容无法更改的字符串(Cocoa或C resp。)的指针。变量仍然可以指向不同的字符串,但原始字符串不会更改其内容。
  • 这与指向char* constNSMutableString* const之类的字符串的常量指针不同,后者是指向可变字符串的常量指针,这意味着字符串本身的内容可以更改,但变量/指针总是指向内存中的相同地址。

研究这个例子:

NSString* str1 = @"A";
NSString* str2 = str1; // points to the same immutable string
NSString* str3 = [str1 stringByAppendingString:@"B"];
// Now str1 and str2 both point to the string "A" and str3 points to a new string "AB"
str2 = str3;
// Now str2 points to the same string as str3 (same memory address and all)
// So str1 points to string "A" and str2 and str3 both point to "B"

请注意,在该示例中,str1尚未更改,仍为"A"。它没有发生变异。 这与另一个例子不同:

NSMutableString* str1 = [NSMutableString stringWithString:@"A"];
NSMutableString* str2 = str1; // points to the same mutable string
[str2 appendString:@"B"];
// Now str1 and str2 still both point to the same string, but
// this same string has been mutated and is now "AB"
// So the string that previously was "A" is now "AB" but is still as the same address in memory
// and both str1 and str2 points to this address so are BOTH equal to string "AB"

在第二个示例中,字符串发生了变异,因此指向此字符串的变量str1str2现在都包含“AB”。

答案 1 :(得分:3)

字符串对象的内容是不可变的。您仍然可以使用指针并使其指向另一个对象。

NSString *s = @"string1";
s = @"string2"

这不会更改第一个字符串对象的内容。它只是分配一个新的字符串对象,并使*s指向它。内存中仍然会有一个字符串对象“string1”(如果你没有使用ARC),没有指向它的东西(稍后会被释放)。

试试这个:

NSString *s = @"string1";
NSLog(@"String object at address %p has content %@.", s, s);
s = @"string2";
NSLog(@"String object at address %p has content %@.", s, s);

Test[1819:303] String object at address 0x100002890 has content string1.
Test[1819:303] String object at address 0x1000028d0 has content string2.

如您所见,在不同的地址创建了一个新实例。

以类名开头的方法(如stringWith...arrayWith...)通常会返回该类的新实例。

您可以使用以下方法之一进行与上述相同的测试:

NSString *s = @"string1";
NSLog(@"String object at address %p ha content %@", s, s);
s = [s substringToIndex:3];
NSLog(@"String object at address %p ha content %@", s, s);

Test[1857:303] String object at address 0x1000028a0 ha content string1
Test[1857:303] String object at address 0x10012ab70 ha content str

答案 2 :(得分:1)

因为您正在更改res指向的内容,而不是更改其指向的内容。