2012-10-19 46 views
3

我是一个Objective-C的新手。我正在为可变性/不可变性的双重概念而挣扎。 我正在翻阅一本名为Programming in Objective-C 4th Edition的书。第15章讨论NSString这个被声明是不可变的类。这本书则提供了一种似乎矛盾的是例如: -困惑于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)]; 

因此,即使“资源”是一个指向一个不可变对象,它的价值几经变化的例子,所以这怎么能叫一成不变?我想我完全忽略了这一点。任何建议,感激地收到。

回答

1

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

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 
+0

我明白了。感谢您的解释。所以这引出了一个问题:如果当指针指向一个新字符串时原始字符串被泄漏,那么改变一个不可变字符串是否是一个好主意? –

+0

好点。它不会泄漏,它会自动释放(一段时间后发布),所以没关系,只要您不会每帧都自动释放数千个字符串或类似的东西。 – DrummerB

4

在下面几行:

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

你不改变字符串的内容“这是串B”(即储存在变量str2),则使变量str2指向一个不同的字符串(即由stringByAppendingString:方法生成的新字符串)。

这里的区别是完全一样的const char*char* const C之间。

  • NSString*const char*均表示一个指向一个字符串(可可或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”。