objective-c 深度复制 NSArray

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/647260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:15:36  来源:igfitidea点击:

Deep copying an NSArray

objective-ccocoa-touchcocoansarraydeep-copy

提问by ivanTheTerrible

Is there any built-in function that allows me to deep copy an NSMutableArray?

是否有任何内置函数可以让我深度复制一个NSMutableArray?

I looked around, some people say [aMutableArray copyWithZone:nil]works as deep copy. But I tried and it seems to be a shallow copy.

我环顾四周,有人说[aMutableArray copyWithZone:nil]作品是深拷贝。但是我试过了,好像是浅拷贝。

Right now I am manually doing the copy with a forloop:

现在我正在手动进行for循环复制:

//deep copy a 9*9 mutable array to a passed-in reference array

-deepMuCopy : (NSMutableArray*) array 
    toNewArray : (NSMutableArray*) arrayNew {

    [arrayNew removeAllObjects];//ensure it's clean

    for (int y = 0; y<9; y++) {
        [arrayNew addObject:[NSMutableArray new]];
        for (int x = 0; x<9; x++) {
            [[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];

            NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
            for (int i = 0; i<[aDomain count]; i++) {

                //copy object by object
                NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
                [[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
            }
        }
    }
}

but I'd like a cleaner, more succinct solution.

但我想要一个更干净、更简洁的解决方案。

回答by Fran?ois P.

As the Apple documentation about deep copiesexplicitly states:

正如关于深拷贝Apple 文档明确指出的那样:

If you only need a one-level-deepcopy:

NSMutableArray *newArray = [[NSMutableArray alloc] 
                             initWithArray:oldArray copyItems:YES];

如果你只需要一层深拷贝:

NSMutableArray *newArray = [[NSMutableArray alloc] 
                             initWithArray:oldArray copyItems:YES];

The above code creates a new array whose members are shallow copies of the members of the old array.

上面的代码创建了一个新数组,它的成员是旧数组成员的浅拷贝。

Note that if you need to deeply copy an entire nested data structure — what the linked Apple docs call a true deep copy— then this approach will not suffice. Please see the other answers here for that.

请注意,如果您需要深度复制整个嵌套数据结构——链接的 Apple 文档称之为真正的深度复制——那么这种方法是不够的。请参阅此处的其他答案。

回答by Andrew Grant

The only way I know to easily do this is to archive and then immediately unarchive your array. It feels like a bit of a hack, but is actually explicitly suggested in the Apple Documentation on copying collections, which states:

我知道轻松做到这一点的唯一方法是存档,然后立即取消存档您的阵列。感觉有点像hack,但实际上在Apple Documentation on copying collections 中明确建议,其中指出:

If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCoding protocol. An example of this technique is shown in Listing 3.

Listing 3 A true deep copy

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
          [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

如果你需要一个真正的深拷贝,比如当你有一个数组时,你可以先归档然后解归档集合,前提是内容都符合 NSCoding 协议。清单 3 中显示了此技术的一个示例。

清单 3 真正的深拷贝

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
          [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

The catch is that your object must support the NSCoding interface, since this will be used to store/load the data.

问题是您的对象必须支持 NSCoding 接口,因为这将用于存储/加载数据。

Swift 2 Version:

斯威夫特 2 版本:

let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData(
    NSKeyedArchiver.archivedDataWithRootObject(oldArray))

回答by Cameron Lowell Palmer

Copy by default gives a shallow copy

默认情况下复制提供浅拷贝

That is because calling copyis the same as copyWithZone:NULLalso known as copying with the default zone. The copycall does not result in a deep copy. In most cases it would give you a shallow copy, but in any case it depends on the class. For a thorough discussion I recommend the Collections Programming Topicson the Apple Developer site.

这是因为调用与使用默认区域复制也称为copy相同copyWithZone:NULL。该copy调用不会产生深拷贝。在大多数情况下,它会给你一个浅拷贝,但无论如何它取决于类。对于彻底的讨论,我推荐Apple Developer 网站上的Collections Programming Topics

initWithArray:CopyItems: gives a one-level deep copy

initWithArray:CopyItems: 给出一层深拷贝

NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];

NSCodingis the Apple recommended way to provide a deep copy

NSCoding是 Apple 推荐的提供深层副本的方式

For a true deep copy (Array of Arrays) you will need NSCodingand archive/unarchive the object:

对于真正的深拷贝(数组数组),您需要NSCoding归档/取消归档对象:

NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

回答by Darshit Shah

For Dictonary

对于字典

NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);

NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);

For Array

对于数组

NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);

NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);

回答by Ben Zotto

No, there isn't something built into the frameworks for this. Cocoa collections support shallow copies (with the copyor the arrayWithArray:methods) but don't even talk about a deep copy concept.

不,框架中没有为此内置任何东西。Cocoa 集合支持浅拷贝(使用 thecopy或 thearrayWithArray:方法),但甚至不谈论深拷贝概念。

This is because "deep copy" starts to become difficult to define as the contents of your collections start including your own custom objects. Does "deep copy" mean everyobject in the object graph is a unique reference relative to everyobject in the original object graph?

这是因为“深拷贝”开始变得难以定义,因为您的集合的内容开始包括您自己的自定义对象。难道“深拷贝”的意思是每一个对象图中的对象是一个独特的相对于基准的每个对象在原来的对象图?

If there was some hypothetical NSDeepCopyingprotocol, you could set this up and make decisions in all of your objects, but unfortunately there isn't. If you controlled most of the objects in your graph, you could create this protocol yourself and implement it, but you'd need to add a category to the Foundation classes as necessary.

如果有一些假设的NSDeepCopying协议,您可以设置它并在所有对象中做出决定,但不幸的是没有。如果您控制了图中的大部分对象,您可以自己创建此协议并实现它,但您需要根据需要向 Foundation 类添加一个类别。

@AndrewGrant's answer suggesting the use of keyed archiving/unarchiving is a nonperformant but correct and clean way of achieving this for arbitrary objects. This book even goes so far so suggestadding a category to all objects that does exactly that to support deep copying.

@AndrewGrant 的回答表明使用键控归档/取消归档对于任意对象来说是一种性能不佳但正确且干净的方法。本书甚至到此为止,因此建议为所有对象添加一个类别,以支持深度复制。

回答by Mrug

I have a workaround if trying to achieve deep copy for JSON compatible data.

如果尝试为 JSON 兼容数据实现深层复制,我有一个解决方法。

Simply take NSDataof NSArrayusing NSJSONSerializationand then recreate JSON Object, this will create a complete new and fresh copy of NSArray/NSDictionarywith new memory references of them.

简单地采取NSDataNSArray使用NSJSONSerialization,然后重新创建JSON对象,这将创建一个完整的新的和新的副本NSArray/NSDictionary与他们的新内存的引用。

But make sure the objects of NSArray/NSDictionary and their children must be JSON serializable.

但是请确保 NSArray/NSDictionary 的对象及其子对象必须是 JSON 可序列化的。

NSData *aDataOfSource = [NSJSONSerialization dataWithJSONObject:oldCopy options:NSJSONWritingPrettyPrinted error:nil];
NSDictionary *aDictNewCopy = [NSJSONSerialization JSONObjectWithData:aDataOfSource options:NSJSONReadingMutableLeaves error:nil];