美文网首页
iOS浅拷贝、深拷贝和完全深拷贝

iOS浅拷贝、深拷贝和完全深拷贝

作者: 小王在努力 | 来源:发表于2018-07-04 15:21 被阅读14次

    1、前言

    最近开发中经常遇到这个问题,不过发现网上能完整的总结的还是很少。今天就动手把这个以我的角度总结一下。尽量把问题说明白:

    2、概念一

    浅拷贝:指针拷贝,两个指针指向同一块内存地址。
    深拷贝:内存块拷贝,两个内存地址完全独立或者说完全不同。

    2.1、关于copy和mutableCopy

    顾名思义,copy就是复制了一个不可变的对象,而mutablecopy就是复制了一个可变的对象。 一个NSObject的对象要想使用这两个函数,那么类必须实现NSCopying协议和NSMutableCopying协议。 对于NSCopying,实现+ copyWithZone:方法。 对于NSMutableCopying,实现+ mutableCopyWithZone:方法。 当然这种情况一般是在自定义结构体时会用,这个我会在后面举例说一下。但经常用的NSString,NSArray,NSDictionary等系统提供的结构体都已实现。

    2.2、举个例子
    NSString、NSMutableString、NSArray、NSMutableArray分别进行copy和mutableCopy时的情况 上面所说的四种结构体可以分为两种类型。
    2.2.1、系统的非容器类对象 这里指的是NSString,NSNumber等等一类的对象。
    2.2.2、系统的容器类对象 指NSArray,NSDictionary等。
    下面我对对这4种结构体分别进行举例,分为8总情况。我会配上相应的内存截图,以方便阅读。

    例子1、对于一个不可变的对象(NSString)
    NSString * string = @"weisheng.wang";
    NSString * stringCopy = [string copy];
    NSString * stringMutableCopy = [string mutableCopy];
    NSLog(@"string:%p",string);
    NSLog(@"stringCopy:%p",stringCopy);
    NSLog(@"stringMutableCopy:%p",stringMutableCopy);

    TodayProject[1347:30830] string:0x712c
    TodayProject[1347:30830] stringCopy:0x712c
    TodayProject[1347:30830] stringMutableCopy:0x79e8d140

    例子2、对于一个可变的对象(NSMutableString)
    NSMutableString * string =[NSMutableString stringWithFormat:@"weisheng.wang"];
    NSString * stringCopy = [string copy];
    NSMutableString * stringMutableCopy = [string mutableCopy];
    NSLog(@"string:%p",string);
    NSLog(@"stringCopy:%p",stringCopy);
    NSLog(@"stringMutableCopy:%p",stringMutableCopy);

    TodayProject[1508:35092] string:0x7a7890d0
    TodayProject[1508:35092] stringCopy:0x7a783400
    TodayProject[1508:35092] stringMutableCopy:0x7a786ef0

    2.2.3、例子1、例子2总结:

    对于系统的非容器类对象(NSString,NSNumber)
    如果对一不可变对象进行复制,copy是指针复制(浅拷贝)而mutableCopy就是内存块复制(深拷贝)。
    如果是对一可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

    例子3、对NSArray进行copy和mutableCopy操作
    NSArray * originArray = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
    NSArray * originArrayCopy = [originArray copy];
    NSMutableArray * originArrayMutableCopy = [originArray mutableCopy];
    [originArrayMutableCopy addObject:@"d"];
    [originArrayMutableCopy removeObjectAtIndex:0];

    1、内存截图: 2de5d8c5dcd37f504b9a6d3088244bfb.png 2、添加一个元素后: 添加一个元素后.png 3、删除一个元素后 171a3558c9c695556288677e4badad98.png
    2.2.4、例子3总结:

    originArray和originArrayCopy是浅复制,而originArrayMutableCopy是深拷贝,originArrayMutableCopy还可以改变数组内的元素:删除或添加。但是注意的是,容器内的元素内容都是浅拷贝。

    例子4、修改元素的值
    NSArray * originArray = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
    NSArray * originArrayCopyArray = [originArray copy];
    NSMutableArray * originArrayMutableCopyArray = [originArray mutableCopy];
    // originArrayMutableCopyArray,originArrayCopyArray和originArray其中的元素都是一样的对象——同一个指针
    //注意:这里只能是将值先取出来通过append来修改,如果用testString = @"d";这样会改变testString的指针,其实是将@“d”临时对象赋给了testString
    NSMutableString * testString = [originArray objectAtIndex:0];
    [testString appendString:@" changevalue"];// 这样以上三个数组的首元素都被改变了

    内存截图

    1、修改值之前 f7fdf23fbd165cda4d17b49ba61fdaa4.png 2、修改值之后 43803eb224bdb298d02f3c955be4b93d.png 3、用testString = @"d"修改值后内存情况,这样以数组中的元素没有任何影响,当然也没有任何意义 6f2baa450093b3b862dba6dd616d9d64.png

    例子5:对NSMutableArray进行copy和mutableCopy操作
    NSMutableArray *originArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil];
    NSArray *originArrayCopy = [originArray copy];
    NSMutableArray *originArrayCopy1 = [originArray copy];
    [originArrayCopy1 addObject:@"d"];//mutable对象copy之后成为imutable对象,所以添加元素会error
    NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];

    内存截图 7e9f01616e6ef74bc79124e0edfb5611.png

    2.2.4、例子4、例子5总结:
    1.对于容器类本身,与非容器类对象的结论相同,即
    如果对一不可变对象进行复制,copy是指针复制(浅拷贝)而mutableCopy就是对象复制(深拷贝)。
    如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
    关键要注意的是复制后容器内对象的变化,比如添加、删除元素,修改某个元素的值。
    2.对于容器而言,其元素对象始终是指针拷贝(浅拷贝)。如果需要元素对象也是深拷贝,就需要实现完全深拷贝。

    3、概念二
    完全深拷贝:指的是容器本身的地址和容器内元素的地址 不一样

    例子6、完全深拷贝的一种实现
    NSArray * array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],[NSString stringWithString:@"b"],@"c",nil];
    NSArray * deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
    NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];

    内存截图: 51d3e7bd2d0c2378fcfa71b62d035699.png

    3.1 例子6总结
    1.trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的元素还是浅拷贝
    2.[deepCopyArray objectAtIndex:0]因为原来是可变对象,还和上面的结论一样,依旧是深拷贝。
    3.用归档的方法实现了真正的元素深拷贝。

    相关文章

      网友评论

          本文标题:iOS浅拷贝、深拷贝和完全深拷贝

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