iOS 之深拷贝与浅拷贝


浅拷贝

浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。如:

char* str = (char*)malloc(100);
char* str2 = str;
浅拷贝只是对对象的简单拷贝,让几个对象共用一片内存,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,要不然会成为野指针。

iOS 里面的浅拷贝:

在 iOS 里面, 使用retain 关键字进行引用计数,就是一种更加保险的浅拷贝。他既让几个指针共用同一片内存空间,又可以在release 由于计数的存在,不会轻易的销毁内存,达到更加简单使用的目的。

深拷贝:

深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。

copy 与 retain 的区别:

copy 是创建一个新对象,retain 是创建一个指针,引用对象计数加一。 copy属性标识两个对象内容相同,新的对象retain count为1, 与旧有对象引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。

iOS里的深拷贝:

这里指的是NSString, NSNumber等等一类的对象。

1
2
3
4
NSString *string = @”dddd";
NSString *stringCopy = [string copy];
NSMutableString *stringDCopy = [string mutableCopy];
[stringMCopy appendString:@ "!!" ];

通过内存发现 ,string和stringCopy指向的是同一块内存区域(weak reference),引用计数没有发生改变。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,是两个独立的字符串内容是一样的。

拷贝构造:

当然在 ios 中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutableCopying协议的类才可以发送mutableCopy消息。

假如发送了一个没有遵守上诉两协议而发送copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。

如果是我们定义的对象,那么我们自己要实现NSCopying , NSMutableCopying这样就能调用copy和mutablecopy了。举个例子:

1
2
3
4
5
6
7
8
@interface MyObj : NSObject<NSCopying, NSMutableCopying>{
     NSMutableString *_name;
     NSString * _imutableStr ;
     int _age;
}     
@property (nonatomic, retain) NSMutableString *name;
@property (nonatomic, retain) NSString *imutableStr;
@property (nonatomic) int age;

copy拷贝构造:

1
2
3
4
5
6
7
- (id)copyWithZone:(NSZone *)zone{
     MyObj *copy = [[[self class] allocWithZone :zone] init];
     copy->name = [_name copy];
     copy->imutableStr = [_imutableStr copy];
     copy->age = age;
     return  copy;
}

mutableCopy拷贝构造:

1
2
3
4
5
6
- (id)mutableCopyWithZone:(NSZone *)zone{
     MyObj *copy = NSCopyObject(self, 0, zone);
     copy->name = [_name mutableCopy];
     copy->age = age;
     return  copy;
}






//+++++++++++++++++++++++++++++++++

iOS开发中,浅复制和深复制要更复杂一些,涉及到集合对象和非集合对象的copy与mutableCopy。

非集合对象:如NSString,NSInteger,NSNumber……

集合对象:如NSArray,NSDictionary,……

1:非集合对象的copy与mutableCopy。

非集合对象的copy与mutableCopy,只需要遵循以下规则即可:

  (1)可变对象的copy和mutableCopy方法都是深复制

  (2)不可变对象的copy方法是浅复制,mutableCopy方法是深复制

  (3)copy方法返回的对象是不可变对象

下面通过代码来验证:

可变对象的copy与 mutableCopy方法:

    //可变对象的复制,copy和mutableCopy都是深拷贝
    NSMutableString *str1 = [NSMutableString stringWithString:@"test"];
    NSMutableString *str2 = [str1 copy];
    //copy返回的是不可变对象,因此str2不能改变,会发生崩溃
    //[str2 appendString:@"test"];
    NSMutableString *str3 = [str1 mutableCopy];
    [str3 appendString:@"test"];
    NSLog(@"%@ %@ %@",str1,str2,str3);
    NSLog(@"%p %p %p",str1,str2,str3);

执行结果:

可以看到,三个字符串的地址是不相同的,说明可变对象的copy和 mutableCopy方法都是深复制。

不可变对象的copy与mutableCopy方法:

NSString *str1 = @"test";
    //直接copy是浅复制
    NSMutableString *str2 = [str1 copy];
    //copy返回的是不可变对象,str2不能被修改,因此会发生崩溃
    //[str2 appendString:@"test"];
    //mutableCopy是深复制
    NSMutableString *str3 = [str1 mutableCopy];
    [str3 appendString:@"test"];
    NSLog(@"%@ %@ %@",str1,str2,str3);
    NSLog(@"%p %p %p",str1,str2,str3);

执行结果:

可以看到:前两个地址一样,第三个地址不一样,因此不可变对象的copy方法是浅复制,mutableCopy方法是深复制。

另外需要注意:无论是可变对象还是不可变对象,copy 方法返回的对象都是不可变的。mu tablecopy方法返回的对象是可变的;



2:集合对象的copy与mutableCopy

实际上,集合对象与非集合对象所遵循的规则基本上是一样的。

可变对象的的copy与mutableCopy 方法

    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    //可变对象copy是深复制
    NSMutableArray *array2 = [array1 copy];
    //copy返回的是不可变对象,array2不能被修改,因此会崩溃
    //[array2 addObject:@"d"];
    //可变对象的mutableCopy是深复制
    NSMutableArray *array3 = [array1 mutableCopy];
    [array3 addObject:@"d"];
    NSLog(@"%p %p %p",array1,array2,array3);

执行结果:

可以看到地址是不一样的。说明可变对象的copy和mutableCopy方法都是深复制。

不可变对象的copy与mutableCopy方法

NSArray *array1 = @[@"a",@"b",@"c"];
    //不可变对象的copy方法,浅复制
    NSArray *array2 = [array1 copy];
    //不可变对象的mutableCopy方法,深复制
    NSArray *array3 = [array1 mutableCopy];
    NSLog(@"%p %p %p",array1,array2,array3);

执行结果:

可以看到,前两个地址一样,第三个地址不一样。说明不可变对象的copy方法是浅复制,mutableCopy方法是深复制。


集合对象和非集合对象的一个差别:

上面说的集合对象的深复制并不是严格意义上的深复制,而是单层深复制。

单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。比如说


NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
调用copy方法   NSArray *array2 = [array1 copy] ,有分配了一块内存,array2指向了这块内存,但是数组内部的元素,

指向的仍然是数组1内部的元素,即内部元素是浅复制。
NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    //可变对象copy是深复制
    NSMutableArray *array2 = [array1 copy];
    //copy返回的是不可变对象,array2不能被修改,因此会崩溃
    //[array2 addObject:@"d"];
    //可变对象的mutableCopy是深复制
    NSMutableArray *array3 = [array1 mutableCopy];
    [array3 addObject:@"d"];
    NSLog(@"%p %p %p",array1,array2,array3);
    NSLog(@"%p %p %p",array1[0],array2[0],array3[0]);

执行结果:

可以看到,三个数组的第一个元素的地址是一样的,也就是说内部元素是浅复制。

3:集合对象的完全复制

集合对象的完全复制,就是集合中的每一层的元素都是深复制。

方法一:

使用

[[NSArray alloc] initWithArray:array1 copyItems:YES];  方法。

NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
    NSLog(@"%p %p",array1,array2);
    NSLog(@"%p %p",array1[0],array2[0]);

执行结果:

可以看到数组元素的地址不一样。

方法二:

先将集合进行归档,然后再解档。代码如下:

    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    NSArray *array2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1 ] error:nil];
    NSLog(@"%p %p",array1,array2);
    NSLog(@"%p %p",array1[0],array2[0]);

执行结果:

可以看到数组元素的地址不一样。



转载自:




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值