我有一个关于对象,记忆和保留的一般性问题。
我不是一个完整的新手(我在iTunes Store上有应用程序销售),但有些东西必须从我身边溜走。我使用Google Docs API,昨天我正在下载电子表格Feed,并枚举结果,即电子表格记录Feed。
枚举并向字典添加对象后,在循环进入下一个Record之前,字典已添加到数组中。因此,经过5次,数组有5个对象,每个记录一个字典,每个都有值。奇怪的是,最后,Array有5份相同的信息。每次循环时,字典都会改变,就像它应该的那样,但是当我将它插入数组时,数组中的其他对象改变为匹配。
我查看了StackOverflow上的一些内容并找到了尝试这个的建议:
[array insertObject:[dictionary copy] atIndex:0];
修复了它。添加复制方法使一切正常。
我只是想知道为什么。
答案 0 :(得分:4)
通常,当一个对象被放入一个数组时,即使原始对象被修改或销毁,它也会保持完整。
你错了。数组(以及Cocoa中的所有其他容器类)从未像这样工作。它们只存储对它们包含的对象的引用(并保留它们),因此如果从数组中检索它们(因为它们是相同的对象),原始对象中的任何更改都会被反映出来。
当然,通过调用copy
,您正在创建字典的副本,所以现在您正在处理单独的对象。同时,您现在正在泄漏内存,因为您负责释放从copy
返回的对象。
另外,请记住copy
仅生成浅副本,因此不会复制复制的词典的实际内容。如果更改词典的内容,这些更改将反映在两个词典中(“原始”词典和已添加到词典中的复制词典)。
答案 1 :(得分:2)
当你将一个对象(我们称之为X)插入一个数组时,实际放入数组的是指针到X的副本,而不是X本身的副本。向X发送retain
消息,以便阵列可以保留它,但不向X发送copy
消息。这意味着稍后对的更改将影响数组中“存储”的对象。
警告: 建议的解决方案会导致大量内存泄漏,因为复制的数据永远不会被释放。更好的解决方案是自动释放复制的数组,以便在释放数组时释放它。
[array insertObject:[[dictionary copy] autorelease] atIndex:0];
或者,对于iPhone代码(其中autorelease can be bad,特别是在循环中):
NSDictionary * newDict = [dictionary copy];
[array insertObject:newDict atIndex:0];
[newDict release];
更新: 请务必阅读Ole Begemann's answer。他对字典的深层和浅层副本提出了一个很好的观点。