iOS 深复制与浅复制

作者: 拾酥 | 来源:发表于2016-09-07 13:49 被阅读0次

这应该是个经典的面试题,网上也有不少相关的文章。但我表示有很多文章我都不能太认同,所以还是打算自己写下。


1.Copy#####

先看一下苹果关于copy的文档:

“The returned object is implicitly retained by the sender, who is responsible for releasing it.The copy returned is immutable”

谁copy谁负责release,返回的对象是不可变的。
下面还是直接看代码。

NSArray *arr1 = @[@1,@2]; 
NSArray *arr2 = [arr1 copy];
NSLog(@"\n arr1 %p \n arr2 %p",arr1,arr2);
//打印出来的内存地址
//arr1 0x100100660 
//arr2 0x100100660
NSMutableArray *marr1 = @[@"one",@"two",@"three",@"four"].mutableCopy;
NSArray *arr = [marr1 copy];
NSLog(@"\n marr1 %p  \n arr %p ",marr1,arr);
//打印出来的内存地址
//marr1 0x1001017c0  
//arr 0x1001018d0 

可以看到,不可变数组copy之后内存地址是一毛一样的,并没有在内存上重新分配空间创建副本,效果跟

NSArray *arr1 = @[@1,@2]; 
NSArray *arr2 = arr1;

是一样的,就是引用持有了而已。而可变数组copy之后在内存创建了新的副本。此刻需要来一张图。。

copy 引用

我的理解是:反正原来的数组是不可变的,copy之后也是不可变的,就没有必要再浪费内存创建新的空间了。而原来的可变数组可能会随时改变,copy之后自然不能引用原数组。

2.MutableCopy#####

照例先看文档:

"The returned object is implicitly retained by the sender, which is responsible for releasing it. The copy returned is mutable whether the original is mutable or not."

大意是:谁污染谁治理。不管原来是不是可变,返回的是可变对象。

NSMutableArray *marr1 = @[@"one",@"two",@"three",@"four"].mutableCopy;
NSMutableArray *marr2 = [marr1 mutableCopy];
NSLog(@"\n marr1 %p \n marr2 %p ",marr1,marr2);
//result
//marr1 0x100504020 
//marr2 0x100504250 
NSArray *arr = @[@1,@2];
NSMutableArray *marr = [arr mutableCopy];
NSLog(@"\n arr %p \n marr %p",arr,marr);
//result
//arr 0x100102ab0 
//marr 0x100102df0

再来一张图:

mutableCopy.png

这就很好理解了,复制出来的对象是可变的,因此肯定要另外分配内存空间,不然只要有一个变大家都跟着变,那就没法玩了。

浅复制与深复制#####

下面我们再来看另外一段代码:

NSMutableArray *marr1 = @[@"one".mutableCopy,@"two".mutableCopy,@"three".mutableCopy,@"four".mutableCopy].mutableCopy;
NSMutableArray *marr2 = [marr1 mutableCopy];
NSMutableString *mStr = marr1[0];
[mStr appendString:@"QWE"];
NSLog(@"\n marr1 = %@ \n  marr2 = %@",marr1,marr2);
//result
/*marr1 = (
oneQWE,
two,
three,
four ) 
marr2 = (
oneQWE,
two,
three,
four) */

可以看到,marr1[0]的值变了。因为我们从数组中获取元素时,得到的是这个元素的一个新引用,但并不是新的副本。mStr和marr1[0]指向内存中的同一个对象。修改mStr实际上就是这个对象被修改了,因此输出的marr1[0] 为"oneQWE"。
但是为什么marr2[0]的值也被改变了呢?这与默认的浅复制有关,它意味着使用mutableCopy复制时,在内存中为新的数组分配了空间,并且将单个元素复制到新数组中。然而将原始数组中的没个元素复制到新位置意味着:仅将引用从一个数组元素复制到了另一个数组元素。这样做的结果是这两个数组中的元素都指向内存中的同一个字符串。这跟一个对象赋值给另一个对象没什么两样。

mStr.png

从这个意义上来看,copy与mutableCopy都是浅复制。那么,怎么实现真正意义上的深复制,将marr1[0]指向的对象也进行拷贝,创建一个新副本呢?答案就是:归档。

NSMutableArray *marr1 = @[@"one".mutableCopy,@"two".mutableCopy,@"three".mutableCopy,@"four".mutableCopy].mutableCopy;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marr1];
NSMutableArray *marr2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSMutableString *mStr = marr1[0];
[mStr appendString:@"QWE"];
NSLog(@"\n marr1 = %@ \n  marr2 = %@",marr1,marr2);
//result
marr1 = (
oneQWE,
two,
three,
four
) 
  marr2 = (
one,
two,
three,
four
)

YYKit里面也有对NSObject的拓展- deepCopy

- (id)deepCopy {
id obj = nil;
@try {
    obj = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self]];
}
@catch (NSException *exception) {
    NSLog(@"%@", exception);
}
return obj;
}

这个这个直接拿来用。。
以上,如有错误,请大神指点。

参考书籍《Objective-C 2.0编程》
参考代码:YYKit

相关文章

  • 深浅复制

    参考链接 iOS 集合的深复制与浅复制

  • iOS

    开发记录 iOS 深复制与浅复制 浅拷贝就是拷贝后,并没有进行真正的复制,而是复制的对象和原对象都指向同一个地址 ...

  • 设计模式 - 原型模式

    注意深复制与浅赋值的问题 C#中如果需要实现深复制,必须实现 ICloneable 接口。

  • iOS 集合的深复制与浅复制

    iOS 集合的深复制与浅复制 概念 对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是...

  • 深拷贝(复制)与浅拷贝(复制)

    对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的栈,也就是复制的结果是两...

  • iOS 深、浅拷贝的理解

    iOS 的深、浅拷贝通过一张图片能够很直观理解: 对于系统的非容器类对象,对不可变对象复制,copy是指针复制(浅...

  • iOS深复制与浅复制

    一、深复制与浅复制 概念 对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对...

  • iOS 深复制与浅复制

    我相信网上大家有很多人看到了关于这个话题,但是我还是写一下.防止自己脑抽的时候可以再看看. 一 概念 浅复制(...

  • iOS 深复制与浅复制

    这应该是个经典的面试题,网上也有不少相关的文章。但我表示有很多文章我都不能太认同,所以还是打算自己写下。 1.Co...

  • iOS 深复制与浅复制

    参考链接:https://www.zybuluo.com/MicroCai/note/50592http://bl...

网友评论

    本文标题:iOS 深复制与浅复制

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