3

我是一个 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'是一个指向不可变对象的指针,它的值已经改变了好几次,那怎么能称为不可变呢?我想我完全没有抓住重点。任何建议,感激不尽。

4

3 回答 3

4

在以下几行中:

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

您不会更改字符串“this is string B”的内容(存储在变量中str2),而是使变量str2指向不同的字符串(由该方法生成的stringByAppendingString:字符串)。

这里的区别与 C 中的const char*和之间的区别非常相似char* const

  • NSString*并且const char*两者都表示指向其内容无法更改的字符串(Cocoa 或 C resp.)的指针。变量仍然可以指向不同的字符串,但原始字符串不会改变其内容。
  • 这与指向类似char* constor的字符串的常量指针不同NSMutableString* 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"

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

于 2012-10-19T15:09:59.220 回答
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
于 2012-10-19T15:03:13.887 回答
1

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

于 2012-10-19T15:02:59.857 回答