使用Obj-C NSString引用与复制

时间:2012-07-18 20:28:38

标签: objective-c memory reference

我确实找到了关于这个主题的一些讨论,但这超出了我目前的理解水平。我正在阅读Kochan的“Objective-C,4e编程”,并在关于NSString对象的部分。首先,我正在玩的代码,所以我可以问我的问题:

NSString *strA = @"StringA";
NSString *strB = @"StringB";
NSLog(@"Value of strA: %@",strA);
NSLog(@"Value of strB: %@",strB);

strB = strA; // strB should point to strA's memory location
NSLog(@"New value of strB: %@",strB); //correctly logs as "StringA"
strA = @"StringA has been changed.";
NSLog(@"New value of strB: %@",strB); //logs as "StringA" still
NSLog(@"New value of strA: %@",strA); //correctly logs as "StringA has been changed"

我的理解是说strB = strA意味着strB指向strA的内存位置,因此对strA的任何更改也会转到strB。但是,这不会发生。 Kochan说它应该是,并且绕过它建议使用

strB = [NSString stringWithString: strA];

从我所看到的,两种方法都有效。我可以说strB = strA,然后更改strA,但是strB仍然保留它收到的值(strA的值只是在更改之前)。

我认为这可能来自NSString是不可变的,但如果是这种情况,为什么我实际上可以在初始化后更改str1和str2的值?我在这里错过了什么?感谢。

4 个答案:

答案 0 :(得分:3)

好像你已经没有足够的答案......

我认为一个或三个图表将帮助您了解代码示例中发生的情况。

首先,您的代码执行此操作:

NSString *strA = @"StringA";
NSString *strB = @"StringB";

这使你的应用程序的内存看起来像这样:

memory diagram 1

左侧是您的本地变量strAstrB。它们只是指向内存中对象的指针。

中间是字符串对象。这些是由编译器在您的应用程序中预先创建的,因为它们出现在您的源代码中。

右边是字符串对象的实际字符。这些也是由编译器在您的应用程序中预先创建的。

接下来,您的代码执行此操作:

strB = strA;

现在您的应用内存如下所示:

memory diagram 2

请注意,您的本地变量strB已更改,但对象和字符未更改。

最后,您的代码执行此操作:

strA = @"StringA has been changed.";

这使你的应用程序的内存看起来像这样:

memory diagram 3

您的本地变量strA已更改,但对象和字符仍未更改。

答案 1 :(得分:1)

  

我的理解是说strB = strA意味着strB是   指向strA的内存位置,因此对strA的任何更改也会   转到strB。

是的,虽然可以更明确地说strBstrA都指向同一个对象。

  

我可以说strB = strA,然后改变strA,但是strB仍然保留了   它收到的值(在更改之前strA的值)。

如果您更改strA,那么您必须使strA指向其他字符串。 NSStrings是不可变的,因此无法更改它们 - 您只能替换它们。所以,如果你说的话:

strA = [strA stringByAppendingString:@"foo"];

然后strA不再指向原始字符串。当然,strB仍然指向原始对象,并且该对象保持不变,因此strA指向的字符串和strB指向的字符串是不同的对象。

  

我在这里缺少什么?

我认为您正在考虑在执行赋值strB = strA;时创建新对象,但实际上两个指针都将在该语句之后指向同一个对象。当你“改变”strA时,就会创建一个新对象。

现在,如果你在讨论 mutable 字符串,那么事情会有所不同,你当然可以改变它们。然后你会遇到这样的情况:

NSMutableString *mstrA = [@"foo" mutableCopy];
NSMutableString *mstrB = mstrA;     // now mstrB points to the same object as mstrA
[mstrA appendString:@"bar"];
NSLog(@"%@", mstrB);                // will log @"foobar" because the string actually changed

答案 2 :(得分:0)

  

我的理解是说strB = strA意味着strB指向strA的内存位置,因此对strA的任何更改也会转到strB。

改变strA的内存位置 - 是的。更改为指向同一位置的完全不相关的指针,现在指向其他位置 - 否。

答案 3 :(得分:0)

有两种方法可以考虑这里发生的事情。一个稍微低一点的是,你正在处理一个名为 pointer 的构造。指针保存内存地址,与int变量保存整数值的方式完全相同。如果您将int分配给另一个int,则更改第一个,第二个不会更改:

int i1 = 10;
int i2 = i1;
i1 = 600;    // i2 still 10

指针也是如此。

另一种(可能更有效)的方式是strAstrB实际上是对象的名称。如果通过一个名称将对象分配给另一个名称,则两个名称都包含相同的对象。除了内存管理和对象生存期之外,您可以将一个名称重新分配给另一个对象,另一个名称将继续指向原始对象。