Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 使用原始元素的可变副本复制NSArray_Objective C_Cocoa_Nsmutablearray_Nsarray_Copying - Fatal编程技术网

Objective c 使用原始元素的可变副本复制NSArray

Objective c 使用原始元素的可变副本复制NSArray,objective-c,cocoa,nsmutablearray,nsarray,copying,Objective C,Cocoa,Nsmutablearray,Nsarray,Copying,我正在类中创建一个字典数组。我想将该数组的副本返回给任何其他请求它的对象。传递给其他对象的此副本需要在不修改原始副本的情况下进行修改 因此,我在类的getter方法中使用了以下内容,该方法包含“master”数组: 然而,这似乎使里面的所有词典都是不可变的。我怎样才能避免这种情况 我想我错过了一些东西。任何帮助都将不胜感激 复制数组将创建数组对象的副本,并引用原始内容对象(适当保留) 根据文档,-initWithArray:copyItems:使用原始数组中项目的副本来初始化新数组。此副本是通过

我正在类中创建一个字典数组。我想将该数组的副本返回给任何其他请求它的对象。传递给其他对象的此副本需要在不修改原始副本的情况下进行修改

因此,我在类的getter方法中使用了以下内容,该方法包含“master”数组:

然而,这似乎使里面的所有词典都是不可变的。我怎样才能避免这种情况


我想我错过了一些东西。任何帮助都将不胜感激

复制数组将创建数组对象的副本,并引用原始内容对象(适当保留)

根据文档,
-initWithArray:copyItems:
使用原始数组中项目的副本来初始化新数组。此副本是通过发送原始内容对象
-copyWithZone:
创建的,这将在可变对象的情况下创建一个不可变副本

如果您需要不同的行为(即内容对象的可变副本,或内容对象的深度副本),您必须编写自己的便利函数/方法来完成此操作。

Jim正确地向每个元素发送消息。要获取数组元素的可变副本,您需要向每个元素发送(或只是为了简洁起见)。这相当简单:

NSMutableArray *masterArray = ...
NSMutableArray *clone = [NSMutableArray arrayWithCapacity:[masterArray count]];
for (id anObject in masterArray)
    [clone addObject:[anObject mutableCopy]]; // OR [clone addObject:anObject];
然而,在您对这个问题的解释中隐藏着一个更深层次的问题:似乎您希望数组及其元素(字典)都是可变的,但有几个要点需要澄清,特别是考虑到您的规定“[the]传递给其他对象的副本需要在不修改原始对象的情况下进行修改。”具体取决于您的意思,这可能非常复杂,难以保证和实现

例如,假设原始数组包含许多可变字典。创建前两个级别的可变副本意味着获得副本的人可以修改自己的数组和数组中的字典,而无需直接更改原始数组或字典。但是,如果字典包含可变对象(如NSMutableArray、NSMutableString等),则使用“副本”的代码可以间接修改字典的内容,只使用对可变副本的引用

可变副本是“浅”的,这意味着只复制第一级,并且副本具有指向与原始结构相同的元素的指针。因此,要保证原件和副本之间没有链接(至少是手动链接),需要扫描整个结构并制作副本。如果某些元素不符合NSCopying或NSMutableCopying,这可能会变得更加复杂

最简单、最快的解决方案是使用上面的简单代码,或者只返回对主数组的引用。这需要相信客户端代码不会修改数组,因此这可能不会在所有情况下都起作用,但如果您也控制调用代码,这可能更可取。另一方面,如果你确实想要一个完全不同的副本,考虑使用NSCoding /KEY存档:

NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];

基本上,这会将所有内容转换为原始数据字节,然后将其重建为一组新的对象。要使其工作,字典中的所有对象都必须符合。这可能需要一点时间,但这是一种保证对象唯一性的优雅通用方法。这当然会带来非零的性能成本,但如果您必须绝对保证不会有副作用,它应该会起作用。

一种方法是滥用键值编码,将
可变副本
发送到每个词典,并将
自动释放
发送到每个副本。但这是一个肮脏的,肮脏的黑客,所以不要这样做。事实上,你可能一开始就不应该这么做

通常,当我看到单词“字典数组”时,我会认为您使用字典作为模型对象的替代品。不要那样做。编写自己的模型类;当您有自己的自定义属性和行为方法可以使用时,一切都会变得容易得多。(有些事情比其他更重要:如果没有合适的模型层,实现AppleScript支持几乎是不可能的。)


一旦有了真实的模型对象,就可以在其中实现
NSCopying
,而不必担心可变和不可变,因为在真实的模型类中可能不会有可变性的区别。(我不知道其他的,但我从来没有在我的模型类中做过这样的区分。)然后你可以使用现有的NSArray
initWithArray:copyItems:
方法。

你可以采取的另一种方法是使用CFPropertyListCreateDeepCopy()函数(在CoreFoundation框架中),为mutabilityOption参数传入kCFPropertyListMutableContainers。代码如下所示:

NSMutableArray* originalArray;
NSMutableArray* newArray;

newArray = (NSMutableArray*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef)originalArray, kCFPropertyListMutableContainers);

这不仅可以创建字典的可变副本,还可以递归地创建这些字典所包含的任何内容的可变副本。但请注意,只有当您的字典数组仅包含有效属性列表(数组、数字、日期、数据、字符串和字典)的对象时,这才有效,因此这可能适用于您的特定情况。

Ew,请不要提及像使用-valueForKey这样的东西:这样新手可以看到并被它误导。(他们会的,你知道:“在互联网上,我读到了制作可变拷贝的方法是……”这是人们会记住的。)我把这一段改得不那么具体,更强烈地反对它。你现在怎么想?那真是一个空洞的编辑奎因。在原文中用逗号来抵消这个短语是完全可以接受的。如果你想成为一个语法纳粹,你仍然需要在“i.e.”后面加一个逗号,甚至在括号内。更不用说在括号后面加一个逗号了。B
NSMutableArray* originalArray;
NSMutableArray* newArray;

newArray = (NSMutableArray*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef)originalArray, kCFPropertyListMutableContainers);