Objective c 被NSString不变性弄糊涂了

Objective c 被NSString不变性弄糊涂了,objective-c,cocoa,nsstring,Objective C,Cocoa,Nsstring,我是一个Objective-C新手。我正在与易变性/不变性这两个孪生概念作斗争。 我正在翻阅一本名为《Objective-C编程》第四版的书。第15章讨论了被声明为不可变的NSString类。然后,本书提供了似乎与此相矛盾的示例,例如: NSString *str1 = @"this is string A"; NSString *str2 = @"this is string B"; str2 = [str1 stringByAppendingString:str2]; NSString

我是一个Objective-C新手。我正在与易变性/不变性这两个孪生概念作斗争。 我正在翻阅一本名为《Objective-C编程》第四版的书。第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”是指向不可变对象的指针,它的值已经更改了好几次,那么如何将其称为不可变对象呢?我想我完全没有抓住要点。感谢您的建议。

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

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

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);

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

以类名称开头的方法(如
stringWith…
arraywhith…
)通常返回该类的新实例

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

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);


在以下行中:

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*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”。

我理解。谢谢你的解释。因此,这就引出了一个问题:如果指针指向新字符串时原始字符串泄漏,那么更改不可变字符串是否是一个好主意?这一点很好。它没有泄露,它是自动释放的(稍后发布),所以只要你不在每帧自动释放数千个字符串或者类似的东西,这就可以了。
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"
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"