美文网首页
iOS - 深拷贝浅拷贝

iOS - 深拷贝浅拷贝

作者: 搬砖的crystal | 来源:发表于2022-07-18 16:54 被阅读0次

    一、基本概念

    浅拷贝

    浅拷贝只是对 object 对象指针进行拷贝,不会开辟新的内存。与数据源指向的是同一内存。例如 copyA = [A copy]capyAA 指向的是同一内存,A 的值变化,copyA 的值也会发生变化。
    copy 方法做的是浅拷贝。

    深拷贝

    深拷贝会开辟新的内容,然后对原数据进行复制,新 object 对象与数据源指向的是不同的内存,对数据源操作不会影响新object 对象。例如 mutableCopyA = [A mutableCopy]mutableCopyAA 指向的是两块不同的内存,A 的值发生变化不会影响到 mutableCopyA 的值。
    mutableCopy 方法做的是深拷贝。
    �####二、不同对象类型的深拷贝和浅拷贝

    1.NSStringNSMutableString
    NSString
        // 不可变字符串
        NSString *str = [NSString stringWithFormat:@"哈哈哈哈哈"];
        NSLog(@"str = %@ :对象地址==%p ,对象指针地址==%p",str ,str, &str);
        NSString *strCopy = [str copy];
        NSString *strMutableCopy = [str mutableCopy];
        str = [NSString stringWithFormat:@"测试"];
    
        NSLog(@"str = %@ :对象地址==%p ,对象指针地址==%p",str ,str, &str);
        NSLog(@"strCopy = %@ :对象地址==%p , 对象指针地址==%p", strCopy,strCopy, &strCopy);
        NSLog(@"mutalbeCopy = %@ :对象地址==%p , 对象指针地址==%p",strMutableCopy, strMutableCopy, &strMutableCopy);
    

    输出结果

    2022-07-18 15:38:47.952442+0800 DJTestDemo[28524:358667] str = 哈哈哈哈哈 :对象地址==0x60000394f540 ,对象指针地址==0x7ff7bdb61b38
    2022-07-18 15:38:47.952607+0800 DJTestDemo[28524:358667] str = 测试 :对象地址==0x600003715ae0 ,对象指针地址==0x7ff7bdb61b38
    2022-07-18 15:38:51.508690+0800 DJTestDemo[28524:358667] strCopy = 哈哈哈哈哈 :对象地址==0x60000394f540 , 对象指针地址==0x7ff7bdb61b30
    2022-07-18 15:38:51.508918+0800 DJTestDemo[28524:358667] mutalbeCopy = 哈哈哈哈哈 :对象地址==0x60000394f300 , 对象指针地址==0x7ff7bdb61b28
    

    针对 NSString 类型来看,copy 后对象地址没有变化,说明copy 只是创建了新的指针,指针指向的还是原来的内存地址。mutalbeCopy 之后对象地址也发生了变化,说明 mutalbeCopy 创建了新的指针,同时开辟了新的内存并将 string 的内容复制了过去。

    NSMutableString
        // 可变字符串
        NSMutableString *mutableString = [NSMutableString stringWithString:@"hello world"];
        NSString *mutableStringCopy = [mutableString copy];
        NSMutableString *mutableStringMutableCopy = [mutableString mutableCopy];
    
        NSLog(@"mutableString: 对象地址==%p , 对象指针地址==%p", mutableString, &mutableString);
        NSLog(@"copy: 对象地址==%p , 对象指针地址==%p", mutableStringCopy, &mutableStringCopy);
        NSLog(@"mutalbeCopy: 对象地址==%p , 对象指针地址==%p", mutableStringMutableCopy, &mutableStringMutableCopy);
    

    输出结果

    2022-07-18 16:00:45.717067+0800 DJTestDemo[30814:386885] mutableString: 对象地址==0x60000233a6d0 , 对象指针地址==0x7ff7be10cca8
    2022-07-18 16:00:45.717308+0800 DJTestDemo[30814:386885] copy: 对象地址==0x600002d10380 , 对象指针地址==0x7ff7be10cca0
    2022-07-18 16:00:45.717418+0800 DJTestDemo[30814:386885] mutalbeCopy: 对象地址==0x60000233aa30 , 对象指针地址==0x7ff7be10cc98
    

    针对 NSMutableString 类型来看,不论是 copy 还是 mutalbeCopy,对象的指针地址和对象地址都发生了变化,因此两种形式都开辟了新内存并将内容复制到的新内存中。

    2. NSArrayNSMutableArray

    按照上面 NSStringNSMutableString 系统非集合类对象的思路,对 NSArrayNSMutableArray 系统集合类对象做同样的示例分析。
    因为集合类对象里面的元素还可以是对象,因此需要打印内部元素的地址信息,查看是否进行了深拷贝。

    NSArray
        NSArray *cellArray1 = @[@"1", @"2", @"3"];
        NSArray *cellArray2 = @[@"4", @"5", @"6"];
        
        NSArray *array = @[cellArray1, cellArray2];
        NSArray *arrayCopy = [array copy];
        NSArray *arrayMutableCopy = [array mutableCopy];
            
        NSArray *tempArray = array.firstObject;
        NSArray *tempArrayCopy = arrayCopy.firstObject;
        NSArray *tempArrayMutableCopy = arrayMutableCopy.firstObject;
        
    
        NSLog(@"      array:对象地址 == %p ,对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", array, &array, tempArray, &tempArray);
        NSLog(@"       copy: 对象地址 == %p ,对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", arrayCopy, &arrayCopy, tempArrayCopy, &tempArrayCopy);
        NSLog(@"mutalbeCopy: 对象地址 == %p ,对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", arrayMutableCopy, &arrayMutableCopy, tempArrayMutableCopy, &tempArrayMutableCopy);
    

    输出结果

    2022-07-18 16:13:17.254829+0800 DJTestDemo[32009:406468]       array:对象地址 == 0x600002343180 ,对象指针地址 == 0x7ff7b3413b10 , firstObject地址 == 0x10caf4c18 , firstObject指针地址 == 0x7ff7b3413af8
    2022-07-18 16:13:17.254992+0800 DJTestDemo[32009:406468]        copy: 对象地址 == 0x600002343180 ,对象指针地址 == 0x7ff7b3413b08 , firstObject地址 == 0x10caf4c18 , firstObject指针地址 == 0x7ff7b3413af0
    2022-07-18 16:13:17.255115+0800 DJTestDemo[32009:406468] mutalbeCopy: 对象地址 == 0x600002d1d470 ,对象指针地址 == 0x7ff7b3413b00 , firstObject地址 == 0x10caf4c18 , firstObject指针地址 == 0x7ff7b3413ae8
    
    NSMutableString
        NSArray *cellArray1 = @[@"1", @"2", @"3"];
        NSArray *cellArray2 = @[@"4", @"5", @"6"];
        NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:@[cellArray1, cellArray2]];
        NSArray *mutableArrayCopy = [mutableArray copy];
        NSMutableArray *mutableArrayMutableCopy = [mutableArray mutableCopy];
        
        NSMutableArray *tempMutableArray = mutableArray.firstObject;
        NSMutableArray *tempMutableArrayCopy = mutableArrayCopy.firstObject;
        NSMutableArray *tempMutableArrayMutableCopy = mutableArrayMutableCopy.firstObject;
        
        NSLog(@"mutableArray: 对象地址 == %p , 对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", mutableArray, &mutableArray, tempMutableArray, &tempMutableArray);
        NSLog(@"        copy: 对象地址 == %p , 对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", mutableArrayCopy, &mutableArrayCopy, tempMutableArrayCopy, &tempMutableArrayCopy);
        NSLog(@" mutalbeCopy: 对象地址 == %p , 对象指针地址 == %p , firstObject地址 == %p , firstObject指针地址 == %p", mutableArrayMutableCopy, &mutableArrayMutableCopy, tempMutableArrayMutableCopy, &tempMutableArrayMutableCopy);
    

    输出结果

    2022-07-18 16:18:30.292810+0800 DJTestDemo[32109:412361] mutableArray: 对象地址 == 0x6000022bcd80 , 对象指针地址 == 0x7ff7b9f8db10 , firstObject地址 == 0x105f7ac20 , firstObject指针地址 == 0x7ff7b9f8daf8
    2022-07-18 16:18:30.292948+0800 DJTestDemo[32109:412361]         copy: 对象地址 == 0x600002cf3520 , 对象指针地址 == 0x7ff7b9f8db08 , firstObject地址 == 0x105f7ac20 , firstObject指针地址 == 0x7ff7b9f8daf0
    2022-07-18 16:18:30.293075+0800 DJTestDemo[32109:412361]  mutalbeCopy: 对象地址 == 0x6000022bcdb0 , 对象指针地址 == 0x7ff7b9f8db00 , firstObject地址 == 0x105f7ac20 , firstObject指针地址 == 0x7ff7b9f8dae8
    
    结论

    copymutableCopy 之后对象地址的变化与非集合对象变化相同。
    无论是 copy 还是 mutableCopy,内部元素的地址都没有变化,只是指针地址发生了变化。
    mutableCopy做的也只是浅层深拷贝。

    3.自定义对象的深拷贝和浅拷贝

    首先自定义对象需要实现 NSCopyingNSMutableCopying 协议。

    #import <Foundation/Foundation.h>
    @interface DJExample : NSObject
    @property (nonatomic, strong) NSString *exampleTitle;
    @end
    
    #import "DJExample.h"
    @interface DJExample()<NSCopying,NSMutableCopying>
    
    @end
    @implementation DJExample
    
    // 实现copyWithZone方法
    - (id)copyWithZone:(NSZone *)zone {
        DJExample *example = [[self class] allocWithZone:zone];
        example.exampleTitle = self.exampleTitle;
        return example;
    }
    
    // 实现mutableCopyWithZone方法
    - (id)mutableCopyWithZone:(NSZone *)zone {
        DJExample *example = [[self class] allocWithZone:zone];
        example.exampleTitle = self.exampleTitle;
        return example;
    }
    
    @end
    
        DJExample *example1 = [[DJExample alloc] init];
        example1.exampleTitle = @"test1";
        
        DJExample *exampleCopy = [example1 copy];
        DJExample *exampleMutableCopy = [example1 mutableCopy];
        
        NSString *title = example1.exampleTitle;
        NSString *titleCopy = exampleCopy.exampleTitle;
        NSString *titleMutableCopy = exampleMutableCopy.exampleTitle;
        
    
    
        NSLog(@"    Example: 对象地址 == %p ,对象指针地址 == %p , 属性地址 == %p ,属性指针地址 == %p", example1, &example1, title, &title);
        NSLog(@"       copy: 对象地址 == %p ,对象指针地址 == %p , 属性地址 == %p ,属性指针地址 == %p", exampleCopy, &exampleCopy, titleCopy, &titleCopy);
        NSLog(@"mutalbeCopy: 对象地址== %p ,对象指针地址 == %p , 属性地址 == %p ,属性指针地址 == %p", exampleMutableCopy, &exampleMutableCopy, titleMutableCopy, &titleMutableCopy);
    

    输出结果

    2022-07-18 16:42:58.667753+0800 DJTestDemo[32713:434463]     Example: 对象地址 == 0x6000034883a0 ,对象指针地址 == 0x7ff7b90b4b38 , 属性地址 == 0x106e4d218 ,属性指针地址 == 0x7ff7b90b4b20
    2022-07-18 16:42:58.667900+0800 DJTestDemo[32713:434463]        copy: 对象地址 == 0x6000034883b0 ,对象指针地址 == 0x7ff7b90b4b30 , 属性地址 == 0x106e4d218 ,属性指针地址 == 0x7ff7b90b4b18
    2022-07-18 16:42:58.668013+0800 DJTestDemo[32713:434463] mutalbeCopy: 对象地址== 0x6000034883c0 ,对象指针地址 == 0x7ff7b90b4b28 , 属性地址 == 0x106e4d218 ,属性指针地址 == 0x7ff7b90b4b10
    

    自定义对象使用 copymutableCopy 之后,对象的地址和指针地址都发生了变化,但是属性地址还是指向原来的地址,也就是说实际也是浅层的深拷贝。
    因为 copyWithZone 方法和 mutableCopyWithZone 都是自己重写的,所以其实自定义对象使用 copy 还是 mutableCopy 并没有什么区别。

    4.数组中的元素是自定义对象时的深拷贝和浅拷贝
        DJExample *example2 = [[DJExample alloc] init];
        example2.exampleTitle = @"test2";
        
        NSArray *exampleArray = [[NSArray alloc] initWithObjects:example2, nil];
        NSArray *shallowCopyArray = [[NSArray alloc] initWithArray:exampleArray];
        NSArray *deepCopyArray = [[NSArray alloc] initWithArray:exampleArray copyItems:YES];
        
        DJExample *shallowCopyExample = shallowCopyArray.firstObject;
        DJExample *deepCopyExample = deepCopyArray.firstObject;
        
        example2.exampleTitle = @"where is test2";
    
        NSLog(@"    exampleArray:对象地址 == %p , 对象指针地址 == %p , 属性地址 == %p , 属性指针地址 == %p , 属性值 == %@", exampleArray, &exampleArray, example2, &example2, example2.exampleTitle);
        NSLog(@"shallowCopyArray: 对象地址 == %p , 对象指针地址 == %p , 属性地址 == %p , 属性指针地址 == %p , 属性值 == %@", shallowCopyArray, &shallowCopyArray, shallowCopyExample, &shallowCopyExample, shallowCopyExample.exampleTitle);
        NSLog(@"   deepCopyArray: 对象地址 == %p , 对象指针地址 == %p , 属性地址 == %p , 属性指针地址 == %p , 属性值 == %@", deepCopyArray, &deepCopyArray, deepCopyExample, &deepCopyExample, deepCopyExample.exampleTitle);
    

    输出结果

    2022-07-18 16:51:22.639103+0800 DJTestDemo[32916:442954]     exampleArray:对象地址 == 0x600003298d20 , 对象指针地址 == 0x7ff7b9279b30 , 属性地址 == 0x6000030b0190 , 属性指针地址 == 0x7ff7b9279b38 , 属性值 == where is test2
    2022-07-18 16:51:22.639313+0800 DJTestDemo[32916:442954] shallowCopyArray: 对象地址 == 0x600003298d20 , 对象指针地址 == 0x7ff7b9279b28 , 属性地址 == 0x6000030b0190 , 属性指针地址 == 0x7ff7b9279b18 , 属性值 == where is test2
    2022-07-18 16:51:22.639472+0800 DJTestDemo[32916:442954]    deepCopyArray: 对象地址 == 0x6000030b01d0 , 对象指针地址 == 0x7ff7b9279b20 , 属性地址 == 0x6000030b0160 , 属性指针地址 == 0x7ff7b9279b10 , 属性值 == test2
    

    从运行结果中可以看出,使用 initWithArray: 方法实现的是浅拷贝,原对象的值发生改变新数组中也会同步改变。
    使用 initWithArray: copyItems: 方法实现的是深拷贝,数组和数组中的对象都会开辟新的内存,因此原数组中的数据发生变化,新数组不会变化。数组中的自定义对象需要实现NSCopying 和 NSMutableCopying 协议。

    相关文章

      网友评论

          本文标题:iOS - 深拷贝浅拷贝

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