美文网首页
OC之数组的copy方法

OC之数组的copy方法

作者: 农村高富帅 | 来源:发表于2017-03-14 17:35 被阅读0次

浅拷贝和深拷贝

苹果官方文档是这样解释的

There are two kinds of object copying: shallow copies and deep copies. The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection.

谷歌翻译

有两种对象复制:浅拷贝和深拷贝。 正常副本是一个浅拷贝,它产生一个新集合,它与原始对象共享对象的所有权。 深度副本从原始文件创建新对象,并将它们添加到新集合。

更直观的解释如下图:

CopyingCollections_2x.png

NSArray的copy

NSArray内部已经实现了NSCopying协议,所以可以直接调用copy方法,假如其内部没实现的话就需要我们自己实现- (id)copyWithZone:(NSZone *)zone方法,否则就会报错。NSMutableArray同理。
而Foundation框架中提供的所有集合默认都是浅拷贝,验证如下

新建Student和Name类,代码挺简单,就不做解释了

@interface Name : NSObject<NSCopying>

@property (nonatomic, copy) NSString *surname; // 姓
@property (nonatomic, copy) NSString *firstName; // 名

@end

@implementation Name

- (id)copyWithZone:(NSZone *)zone{
    Name *copy = [[[self class] allocWithZone:zone] init];
    return copy;
}

@end

@interface Student : NSObject<NSCopying>

@property (nonatomic, strong) Name *name;
@property (nonatomic, strong) NSString *address;

@end

@implementation Student

- (instancetype)init {
    self = [super init];
    if (self) {

    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    Student *copy = [[[self class] allocWithZone:zone] init];
    copy.name = [self.name copy];
    return copy;
}
@end

然后,构建NSArray,通过mutableCopy拷贝一份并打印拷贝前后两者的地址进行比较,代码如下

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;

    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [studentsArray mutableCopy];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);

打印结果

studentsArray[0]:0x1002013b0
studentsArrayCopy[0]:0x1002013b0
studentsArrayAddress:0x100203210
studentsArrayCopyAddress:0x100203320

可见studentsArray(原数据)和studentsArrayCopy(拷贝后的数据)地址是不同的,而数组中的元素的地址相同,可见通过mutableCopy方法实现的拷贝是浅拷贝。

数组还提供了一种copy方法,- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;,flag表示是否把数组元素也拷贝一份,如果数组的元素没有实现NSCopying协议而且flag设置成YES的话,调用该方法是会Crash的。如果数组中的所有层级都实现了NSCopying方法的话,这种方式的拷贝就是所谓的深拷贝,即完全复制一份。验证如下

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;
    
    
    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [[NSMutableArray alloc] initWithArray:studentsArray copyItems:YES];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);
    
    Name *nameCopy = ((Student *)studentsArrayCopy[0]).name;
    NSLog(@"\nname:%p",name);
    NSLog(@"\nnameCopy:%p",nameCopy);

打印结果如下

studentsArray[0]:0x100300070
studentsArrayCopy[0]:0x100300930
studentsArrayAddress:0x100300700
studentsArrayCopyAddress:0x100300a00
name:0x100300130
nameCopy:0x1003009e0

所有的原对象和copy对象都不同,可见是深拷贝。当我们要实现复制一个数组并在操作之后对原数组无影响的需求时就可以通过这种方式。
当然,如果数组层次很多的话,这方式明显不可取,幸运的是苹果提供了一种更简单的实现方式(本人没验证过)

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

还有,- (instancetype)initWithArray:(NSArray<ObjectType> *)array;这种拷贝方式和- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;方式是一样的,当后者的flag设置成NO的时候,这两个这两方法是完全相同的。而且这样方式和直接调用copy方式的拷贝也是一样的

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;
    
    
    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [[NSMutableArray alloc] initWithArray:studentsArray copyItems:NO];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);
    
    Name *nameCopy = ((Student *)studentsArrayCopy[0]).name;
    NSLog(@"\nname:%p",name);
    NSLog(@"\nnameCopy:%p",nameCopy);

打印结果

studentsArray[0]:0x1004041d0
studentsArrayCopy[0]:0x1004041d0
studentsArrayAddress:0x1004060c0
studentsArrayCopyAddress:0x100406260
name:0x100405ef0
nameCopy:0x100405ef0

数组地址不同,内部元素相同。没毛病。

总结

  • 浅拷贝:
    1, 直接调用copy/mutableCopy方法
    2, [[NSMutableArray alloc] initWithArray:studentsArray copyItems:NO]
    3, [[NSMutableArray alloc] initWithArray:studentsArray]
  • 深拷贝:
    1, [[NSMutableArray alloc] initWithArray:studentsArray copyItems:YES],前提要自己实现每一层级的NSCopying协议
    2, [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]]

参考链接:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

相关文章

  • OC之数组的copy方法

    浅拷贝和深拷贝 苹果官方文档是这样解释的 There are two kinds of object copyin...

  • NSArray copy stong 问题

    先定义几个temp数组 对 ( copy*) NSArry = NSMutableArry进行测试 总结 OC 语...

  • OC数组样式copy

    //这里方法用来 根据detailArray的层级结构 要把idarray 分离成二维数组 - (NSArray*...

  • Swift中如何深拷贝Array中的对象

    我们在开发中会经常使用到数组,在OC中数组可以copy或者mutableCopy,但是在Swift中数组就不能直接...

  • Copy & MutableCopy

    copy&mutableCopy介绍   copy和mutableCopy,深浅拷贝,在OC里面是两个协议方法NS...

  • Swift3 Array 赋值研究

    数组NSArray继承自NSObject,属于对象, 包含Copy的方法,然而Swift的数组是struct,没有...

  • C# 拆分byte[]数组

    将数组进行拆分,使用System.Array.Copy方法进行拆分。比如,原数组byte[] newData = ...

  • OC之Copy语法

    概念 内存管理 NSString的copy实例 对象的copy实例一、概念目的:在改变原有对象的时候,不会改变新对...

  • JAVA基础知识之ArrayList

    今天简单说下ArrayList,底层实现为数组 增加删除方法都是通过数组copy方法,之后再增加size大小 以下...

  • 如何让程序尽量减少内存泄漏

    1.非ARC * Foundation对象(OC对象) : 只要方法中包含了alloc\new\copy\muta...

网友评论

      本文标题:OC之数组的copy方法

      本文链接:https://www.haomeiwen.com/subject/kiwcnttx.html