【问题标题】:Reference vs. Copy with Obj-C NSString使用 Obj-C NSString 引用与复制
【发布时间】:2012-07-18 20:28:38
【问题描述】:

我确实找到了一些关于这个话题的讨论,但这超出了我目前的理解水平。我正在阅读 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 的值?我在这里想念什么?谢谢。

【问题讨论】:

  • @andrewnc 欢迎来到 StackOverflow!请为正确的答案投票并接受最好的答案(或者,如果有相同的答案,第一个正确的答案)。

标签: objective-c memory reference


【解决方案1】:

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

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

首先,您的代码会这样做:

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

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

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

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

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

接下来,您的代码会这样做:

strB = strA;

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

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

最后,您的代码会这样做:

strA = @"StringA has been changed.";

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

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

【讨论】:

  • 这很好地解释了它。非常感谢!
【解决方案2】:

我的理解是说 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 时,就会创建一个新对象。

现在,如果您谈论的是 可变 字符串,情况会有所不同,您当然可以更改它。那么你会遇到这样的情况:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      指针也是如此。

      另一种(可能更高效)的思考方式是strAstrB 实际上是对象的名称。如果您通过一个名称将对象分配给另一个名称,则两个名称都包含同一个对象。抛开内存管理和对象生命周期的问题不谈,您可以将一个名称重新分配给不同的对象,而另一个名称将继续指向原始对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-24
        • 2021-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-09
        相关资源
        最近更新 更多