如何创建 NSArray 的副本并在不影响原始 NSArray 的情况下更改它?

How to create copy of NSArray and change it without affection original NSArray?

我需要 NSArray 的副本来存储日期状态。我尝试使用 mytableCopy,据我所知,它制作了独立于原始对象的副本。

当我对 mutableCopy 进行更改时,我也在原始数组中进行了更改。

为什么?

我的代码是:

_nsarr = [[NSArray alloc] initWithArray:inputArray];
_nsMraa= [NSMutableArray alloc];
_nsMraa = [_nsarr mutableCopy];

注意:两个数组都是我对象的属性。 inputArray 是输入参数,之后就不用了。

备注:一个对象是 NSArray,另一个是 NSMutableArray

试试这个

_nsMraa = [[NSArray alloc]initWithArray:_nsarr copyItems:YES];

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

  • 真正的深拷贝

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

正如 Bharat 和 Milan 所暗示的,NSArray 是一个引用类型数组,它包含一个指针数组。调用 mutableCopy 将生成数组的浅表副本并使副本可变,原始数组仍然是不可变的。但是,mutableCopycopy 都不会对数组的内容执行深层复制。可变或不可变的是数组,而不是数组中保存的对象的内容。

假设如下:

@interface MyObject
- (int) state;
- (void) setState:(int) state;
@end

...

_nsarr = [NSArray arrayWithObject:[[MyObject alloc] initWithState]];
_nsmarr = [_nsarr mutableCopy];

此时你有两个不同的数组,_nsarr_nsmarr,一个是不可变的,而另一个是 _nsarr[0]_nsmarr[0] 仍然是同一个对象,这意味着 [_nsarr[0] setState:1] 是有效的,并且它与 [_nsmarr[0] setState:1]

具有完全相同的效果
[_nsarr[0] setState:1];
NSLog("%d", [_nsmarr[0] state]);   // ==> 1

[_nsarr[0] setState:2];
NSLog("%d", [_nsmarr[0] state]);   // ==> 2

要复制数组中包含的单个对象,您需要创建数组的 "deep" 副本,这意味着要(递归地)复制数组的内容以及数组本身。没有快速简便的方法来创建数组的深拷贝,因为它在很大程度上取决于您如何(如果?)对引用的对象进行深拷贝。 Bharat 提出了一种方法(由于它对对象进行序列化和反序列化,并且要求它们遵守 NSCoding,因此成本略高)一种方法可能类似于:

_nsmarr = [NSArray withCapacity:[_nsarr count]];
for(MyObject* foo in _nsarr) {
    [_nsmarr addObject:[foo copy]];
}

假设 foo 实现了 NSCopying 协议,这在本质上与 initWithArray:copyItems 相同:Milan 建议的方法:

_nsmarr = [[NSMutableArray alloc] initWithArray:_nsarr copyItems:YES];