NSMutableArray中的addObject是被复制还是被保留?

5

当你将对象添加到集合中,比如NSMutableArray,这个对象是被复制的,也就是值语义,还是被保留的,也就是引用语义?

我在这个例子中感到困惑:

NSMutableString *testStr = [@"test" mutableCopy];
NSMutableArray *arrayA = [[NSMutableArray alloc] init];

[arrayA addObject:testStr];
NSLog(@"%@", arrayA);    // output: test

testStr = [@"world" mutableCopy];
NSLog(@"%@", arrayA);    // output: test

// testStr is copied - value semantics

NSMutableArray *testArr = [@[@1, @2] mutableCopy];
NSMutableArray *arrarB = [[NSMutableArray alloc] init];

[arrarB addObject:testArr];
NSLog(@"%@", arrarB);      // output: [1, 2]

[testArr addObject:@3];
NSLog(@"%@", arrarB);      // output: [1, 2, 3]

// testArr is retained - reference semantics

你可以看到:如果对象是一个NSMutableString,它看起来像是对象被复制了——你改变对象不会影响数组中的对象。
然而,如果对象是一个NSMutableArray,当你改变对象时,数组中的对象也会被改变——就像你保留对象或通过引用传递一样。
这里有什么我漏掉的吗? 谢谢。

从技术上讲,它保存了指针引用。这就是为什么您不能将非对象放入任何Cocoa容器中的原因。 - Desdenova
有点旁注,但您可以使用NSHashTable作为列表,允许您指定它如何处理添加到其中的对象引用。 您可以将给定实例的默认行为设置为弱、强或甚至是复制。 更多信息请参见:http://nshipster.com/nshashtable-and-nsmaptable/ - Mick MacCallum
5个回答

4
在你的第一部分中,将一个对象添加到数组中并没有进行复制。让我们看一下你的代码:
在这里,您创建了NSMutableString和NSMutableArray:
NSMutableString *testStr = [@"test" mutableCopy];
NSMutableArray *arrayA = [[NSMutableArray alloc] init];

然后将您的字符串添加到数组中:
[arrayA addObject:testStr];
NSLog(@"%@", arrayA);    // output: test

接下来你要创建一个新的NSMutableString,并将其赋值给变量testStr,这只是让testStr指向了新对象。它对你创建的第一个字符串没有影响:

testStr = [@"world" mutableCopy];
NSLog(@"%@", arrayA);    // output: test

所以这就是为什么你的第一个代码块能够正常工作的原因。
在你的第二个代码块中,看起来你已经理解了它为什么能够正常工作,但是为了让它更清晰明了,testArr 总是指向同一个数组,你也将它添加到了 arrarB 中,因此打印出 arrarB 反映了你对 testArr 所做的更改。

4
集合会保留添加到其中的对象,而不是复制它们。

请注意,NSDictionary会复制键,但不会复制对象。可以使用CFDictionaryRetainCallBack创建CFDictionaryRef以复制对象,并将其(无需桥接)转换为NSDictionary。或者设置NSHashTable以复制对象。 - Borys Verebskyi

2

字符串也会在以下代码中保留:

testStr = [@"world" mutableCopy];

你创建了一个新的字符串,并将其拷贝分配给testStr本地变量,所以旧的保留字符串仍然在表中。


0

不是:

testStr = [@"world" mutableCopy];

你可以尝试:

[testStr setString:@"world"];

这会修改“旧”的字符串,而不是使testStr指向一个新对象。


-1
NSMutableString *testStr = [@"test" mutableCopy];
NSMutableArray *arrayA = [[NSMutableArray alloc] init];
[arrayA addObject:testStr];
NSLog(@"%@", arrayA);    // output: test

testStr = [@"world" mutableCopy];
NSLog(@"%@", arrayA);    // output: test

这里testStr没有被复制到arrayA中。在将testStr对象添加到数组后,testStr指针本身会更改为引用其他对象(假设是“World”)。

与您对数组所做的操作相同,您也可以将另一个字符串附加到testStr中(而不是指向不同的字符串),您可以看到与testArr相同的结果。

  [testStr appendString:@" Test 2"];
`NSLog(@"%@", arrayA);`    // output: test Test 2

我对这个答案有些矛盾的感觉。第一个示例根本没有证明是否发生了复制,而第二个示例则有所证明。 - André Fratelli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接