我是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?我想我完全忽略了这一点。任何建议,感激不尽。
答案 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* const
或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”。
答案 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
指向的内容,而不是更改其指向的内容。