iOS 浅复制和深复制

前言:

提到iOS中的浅复制和深复制的区别,大家都知道浅复制过来的是对象的地址,而深复制,相当于重新开辟了内存控件,存储这个对象。


用代码说话

①单个对象的浅复制与深复制

/// 单个对象 浅复制、深赋值
- (void)ordinaryCopyVSMutableCopy {
    
    NSString *str = @"hehe";
    NSLog(@"源字符:%p",str);
    
    //浅
    NSString *cStr = [str copy];
    NSLog(@"浅复制: Cstr = %p",cStr);
    
    NSString *temp = [str copyWithZone:nil];
    NSLog(@"copyWithZone: temp = %p",temp);
    
    //深
    NSString *mStr = [str mutableCopy];
    NSLog(@"深复制: mStr = %p",mStr);
}

输出结果:

单个对象深浅复制输出结果.png
tips:可以看到 copycopyWithZone方法都是浅复制,对象的地址并没有改变,而mutableCopy重新开辟了内存控件,是深复制

数组及集合类对象的浅复制、深复制、完全复制

我们先定义一个原始数组

NSArray *originArr = [NSArray arrayWithObjects:@"1",@"2", nil];
NSLog(@"原数组 地址:%p",originArr);
NSLog(@"原数组中对象的地址: %p,%p \n",originArr[0],originArr[1]);

看代码:

①对数组进行浅复制
//对数组进行浅复制
  NSArray *copyArr = [originArr copy];
  NSLog(@"浅复制 地址:%p",copyArr);
  NSLog(@"浅复制数组中对象的地址: %p,%p \n",copyArr[0],copyArr[1]);

对比输出结果看:

数组浅复制结果对比.png
tips:可以看到 不论是数组本身还是数组中的元素,地址都没有发生变化,这就是完完全全的浅复制
那么问题1:[NSArray arrayWithArray:originArr] 是浅复制 还是 深复制呢

 NSArray *arr = [NSArray arrayWithArray:originArr];
 NSLog(@"arrayWithArray深复制 地址:%p",arr);
 NSLog(@"arrayWithArray深复制数组中对象的地址: %p,%p \n",arr[0],arr[1]);

结果:

arrayWithArray结果.png
tips:arr相比于源数组,算是一次深复制,但是数组中的元素地址依旧没有发生变化

②对数组进行深复制
 NSArray *mCopyArr = [originArr mutableCopy];
 NSLog(@"深复制 地址:%p",mCopyArr);
 NSLog(@"深复制数组中对象的地址: %p,%p \n",mCopyArr[0],mCopyArr[1]);

打印地址发现:

数组深复制.png]
可以发现mCopyArr相比于原先的数组算是深复制了,但是内部的元素依旧是原先数组中的元素

问题2:[[NSArray alloc] initWithArray:.... copyItems:true] 是浅复制 还是 深复制呢

 NSArray *array = [[NSArray alloc] initWithObjects:[[NSMutableString alloc] initWithString:@"1"], @"2",nil];
 NSLog(@"array 地址: %p",array);
 NSLog(@"array中元素的地址 :%p,%p",array[0],array[1]);
    
 NSArray *arrWithCopyItem = [[NSArray alloc] initWithArray:array copyItems:true];
 NSLog(@"arrWithCopyItem深复制 地址:%p",arrWithCopyItem);
 NSLog(@"arrWithCopyItem深复制数组中对象的地址: %p,%p \n",arrWithCopyItem[0],arrWithCopyItem[1]);

输出结果:

copyItems深复制、浅复制测试.png
可以看到,arrWithCopyItem对于源数组array中的可变对象进行的是深复制,对不可变对象做的是浅复制,所以可以称,[[NSArray alloc] initWithArray:.... copyItems:true]方法是与源数组做了一次不完全的深复制,对于其中的不可变对象依旧是浅复制
tips:字典的[NSDictionary alloc] initWithDictionary:... copyItems:..这个方法结果同上

问题来了:这不算真正意义上的深复制,即完全复制,那__用什么方法可以实现完全复制呢?__

②对数组进行**完全复制**

方法有很多种,这里简单介绍两种:
一:归档、解挡操作

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:originArr];
NSData *aData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSArray *mmCopyArr = (NSArray *)aData;
NSLog(@"①归档深复制 地址:%p",mmCopyArr);
NSLog(@"①归档深复制数组中对象的地址: %p,%p \n",mmCopyArr[0],mmCopyArr[1]);

源数组.png
归档、解档后.png
可以看到,不仅数组本身为深复制,数组中的元素也都重新开辟了内存空间

二:对数组进行遍历深复制,该方法较为简单,就不写代码了

Github项目地址

点击去我的Github下载Demo

Comments
Write a Comment