美文网首页
IOS开发之深拷贝与浅拷贝

IOS开发之深拷贝与浅拷贝

作者: toro宇 | 来源:发表于2018-08-01 15:05 被阅读3次

    拷贝的方式有两种:浅拷贝和深拷贝。 从字面意思理解,浅拷贝,只是拷贝了对象的指针,而不是拷贝对象本身。 深拷贝,是直接拷贝整个对象的内存到另一块内存中。

    拷贝总共可分为三种情况: 浅拷贝、深拷贝、单层深拷贝

        1. 浅拷贝(shallow copy):在浅拷贝操作时,对于被拷贝对象的每一层都是指针拷贝。
        2. 深拷贝(one-level-deep copy):在深拷贝操作时,对于被拷贝对象,至少有一层是深拷贝。
        3. 完全拷贝(real-deep copy):在完全拷贝操作时,对于被拷贝对象的每一层都是对象拷贝
    

    (一)关于copy和mutableCopy
    顾名思义,copy就是复制了一个imutable的对象,而mutablecopy就是复制了一个mutable的对象。
    一个NSObject的对象要想使用这两个函数,那么类必须实现NSCopying协议和NSMutableCopying协议。
    对于NSCopying,实现+ copyWithZone:方法。
    对于NSMutableCopying,实现+ mutableCopyWithZone:方法。
    当然这种情况一般是在自定义结构体时会用,这个我会在后面举例说一下。但经常用的NSString,NSArray,NSDictionary等系统提供的结构体都已实现。
    (二)NSString、NSMutableString、NSArray、NSMutableArray分别进行copy和mutableCopy时的情况
    上面所说的四种结构体可以分为两种类型。
    1.系统的非容器类对象
    这里指的是NSString,NSNumber等等一类的对象。

    2.系统的容器类对象
    指NSArray,NSDictionary等。

    下面对这4种结构体分别进行举例,分为8总情况。我会配上相应的内存截图。以方便阅读。
    例1:对NSString进行copy和mutableCopy操作

    NSString *originStr = @"origin";
    NSString *originStrCopy = [originStr copy];
    NSMutableString *originStrMutableCopy = [originStr mutableCopy];
    

    内存截图:


    image.png

    例2:对NSMutableString进行copy和mutableCopy操作

    NSMutableString *mutableOriginStr =[NSMutableString stringWithString: @"mutableOrigin"];
    //注意这里下面两行代码前面的声明
    NSString *mutableOriginStrCopy = [mutableOriginStr copy];
    NSMutableString *mutableOriginStrCopy1 = [mutableOriginStr copy];
    //这里会报错,因为copy生成的是imutable对象,所以不管声明是什么样的,依旧是imutable的
    [mutableOriginStrCopy1 appendString:@"error"];
    NSMutableString *mutableOriginStrMutableCopy = [mutableOriginStr mutableCopy];
    
    内存截图: image.png

    总结:
    对于系统的非容器类对象,
    如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。
    如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

    例3:对NSArray进行copy和mutableCopy操作

    NSArray *originArray = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
    NSArray *originArrayCopy = [originArray copy];
    //originArray是和originArray同一个NSArray对象(指向相同的对象),包括originArray里面的元素也是指向相同的指针,此处可以看到copy的作用也相当于retain
    NSLog(@"originArray retain count: %ld",(unsigned long)[originArray retainCount]);
    NSLog(@"originArray retain count: %ld",(unsigned long)[originArrayCopy retainCount]);
    NSMutableArray *originArrayMutableCopy = [originArray mutableCopy];
    //originArrayMutableCopy是originArray的可变副本,指向的对象和originArray不同,但是其中的元素和originArray中的元素指向的是同一个对象。originArrayMutableCopy还可以修改自己的对象
    [originArrayMutableCopy addObject:@"d"];
    [originArrayMutableCopy removeObjectAtIndex:0];
    

    内存截图:

    1.操作前: image.png

    2.添加一个元素后:


    image.png

    3.删除一个元素后:


    image.png

    总结:
    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"];// 这样以上三个数组的首元素都被改变了
    

    内存截图


    image.png

    2.修改值之后


    image.png

    3.用testString = @"d"修改值后内存情况,这样以数组中的元素没有任何影响,当然也没有任何意义

    image.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];
    

    内存截图


    image.png

    总结:
    1.对于容器类本身,与非容器类对象的结论相同,即

    如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。
    如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
    关键要注意的是复制后容器内对象的变化,比如添加、删除元素,修改某个元素的值。
    2.对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。

    例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]];
    

    内存截图:


    image.png

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

    相关文章

      网友评论

          本文标题:IOS开发之深拷贝与浅拷贝

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