深拷贝浅拷贝

参考链接:

ios深拷贝,浅拷贝,拷贝自定义对象的简单介绍 - daiyelang的专栏 - 博客频道 - CSDN.NET 

IOS ----- 对象复制_Ives_新浪博客 

copy分为深拷贝、浅拷贝。copy的目的是改变副本的时候不影响原对象。

copy的方法有:

- (id)copy;

- (id)mutableCopy;

深拷贝:内容拷贝(对象中的每一个变量都进行了拷贝),创建了新的对象,新对象引用计数为1,原对象引用计数不变。

浅拷贝:指针拷贝,没有创建新对象,原对象引用计数增加1。

copy 返回的是不可变对象,MutableCopy返回的是可变对象。

一个对象想要支持copy就必须遵从 NSCopying 或者 NSMutableCopying
协议,Foundation框架下默认支持copy的对象类型有:NString、NSArray、NSNumber、NSDictionar、NSMutableString、NSMutablerArray、NSMutableDictionary等,我们也可以让自定义对象支持复制,前提就是必须遵循NSCopying或者NSMutableCopying协议。

以下以字符串为例:

1.不可变字符串调用copy实现拷贝。(浅拷贝)

NSString *originalStr = [[NSString alloc] initWithString:@"abcde"];

NSLog(@"originalStr.retainCount  %p",originalStr);

NSString *newStr = [originalStr copy];

NSLog(@"originalStr.retainCount  %p",originalStr);

NSLog(@"newStr.retainCount  %p",newStr);

打印结果如下:

originalStr.memoryAddress  0x100004230

originalStr.memoryAddress  0x100004230

newStr.memoryAddress  0x100004230

newStr的地址和originalStr的地址相同,可知不可变字符串调用copy为浅拷贝(指针拷贝),联想本篇开头说的:copy的目的是改变副本的时候不影响源对象,因为源对象本身就是不可变的,所以这里使用简单的浅拷贝(指针拷贝)即可实现不影响源对象的需求(也是为了性能着想),所有此处copy直接就返回了源对象。

2. 不可变字符串调用mutableCopy实现拷贝 (深拷贝)

NSString *originalStr = [[NSString alloc] initWithString:@"abcde"];

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSMutableString *newStr = [originalStr mutableCopy];  //返回对象是可变的。

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSLog(@"newStr.memoryAddress  %p",newStr);

打印地址如下:

originalStr.memoryAddress  0x100004230

originalStr.memoryAddress  0x100004230

newStr.memoryAddress  0x100400000

newStr的地址与originalStr的地址不同,可知是创建了新的对象。是深拷贝

3.可变字符串调用copy(深拷贝)

NSMutableString *originalStr = [NSMutableString stringWithFormat:@"%@",@"abcde"];

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSString *newStr = [originalStr copy];

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSLog(@"newStr.memoryAddress  %p",newStr);

打印地址如下:

originalStr.memoryAddress  0x100206d70

originalStr.memoryAddress  0x100206d70

newStr.memoryAddress  0x656463626155

newStr的地址与originalStr的地址不同,可知也进行了深拷贝。

4.可变字符串调用mutableCopy(深拷贝)

NSMutableString *originalStr = [NSMutableString stringWithFormat:@"%@",@"abcde"];

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSMutableString *newStr = [originalStr mutableCopy]; //返回字符串为可变的

NSLog(@"originalStr.memoryAddress  %p",originalStr);

NSLog(@"newStr.memoryAddress  %p",newStr);

//newStr拼接字符串,查看是否会影响originalStr

[newStr appendFormat:@"just a test!"];

NSLog(@"originalStr=======%@",originalStr);

NSLog(@"newStr============%@",newStr);

打印结果如下:

originalStr.memoryAddress  0x100206d70

originalStr.memoryAddress  0x100206d70  //原可变字符串地址

newStr.memoryAddress  0x100300600   //newStr字符串地址

originalStr=======abcde     //newStr拼接后原字符串内容

newStr============abcdejust a test!  //newStr拼接后newStr字符串内容

originalStr和newStr的地址不同,说明创建了新的对象。newStr可进行拼接,说明返回的是可变字符串。

结论:只有不可变对象使用copy的时候才是浅拷贝(指针拷贝),其它三种情况均是深拷贝(内容拷贝)。


实现自定义对象的copy:

1 创建model类 House

@property (nonatomic, copy) NSString *houseId

@property (nonatomic, copy) NSString *houseAddress;

@property (nonatomic, copy) NSString *housePics;

2 遵循协议<NSCopying>

3 实现- (id)copyWithZone:(NSZone*)zone方法

- (id)copyWithZone:(NSZone *)zone

{

House *house = [[[self class] allocWithZone:zone] init];

house.houseId = [_houseId copy];

house.houseAddress = [_houseAddress copy];

house.housePics = [_housePics copy];

return house;

}

在使用该类对象的地方即可使用copy复制该对象。

问题思考:在属性中修饰NSString,NSArray等不可变类型的属性为什么用copy比较合适,用strong进行修饰会出现什么问题?

直接上代码。。。

假设House中的houseId使用strong进行修饰:

@property (nonatomic, strong) NSString *houseId;

在main.m文件中实现如下代码:

NSMutableString *muStr = [NSMutableString stringWithFormat:@"%@",@"15000"];  //可变字符串

House *house = [[House alloc] init];

house.houseId = muStr;  //为houseId赋值

NSLog(@"house.houseId  %@",house.houseId);  //第一次houseId的结果

[muStr appendFormat:@"----------16000"];  //修改muStr的内容

NSLog(@"house.houseId  %@",house.houseId);

打印结果如下:

house.houseId  15000

house.houseId  15000----------16000

此时的打印结果显示,house.houseId发生了改变,而事实上houseId是NSString类型的数据,程序就会发生隐形bug。至于问题出现的原因在house.m中,代码如下

此时在House.m文件中,setterHouseId事实上是这样的

- (void)setHouseId:(NSString *)houseId

{

if (![_houseId isEqualToString:houseId]) {  

[_houseId release];  

_houseId = [houseId retain];   //houseId是可变的字符串,strong进行修饰的情况下这里只是进行了额retain操作。只是简单的浅拷贝,所有会出现问题。

}

}

把NSString类型的houseId使用copy进行修饰,打印结果如下:

house.houseId  15000

house.houseId  15000

此时houseId不会发生异常,原因如下:

- (void)setHouseId:(NSString *)houseId

{

if (![_houseId isEqualToString:houseId]) {

[_houseId release];

_houseId = [houseId copy];//在使用copy修饰的情况下,houseId是一个可变的字符串,进行了copy操作,进行了额深拷贝,创建了一个新的不可变字符串赋值给了_houseId,所以每次进行setter操作都创建了一个新的不可变字符串,不会发生问题。

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 面试中我们经常会问到copy!为什么选择使用copy?原因是NSString属性可能被传入一个NSString实例...
    马戏团小丑阅读 498评论 0 2
  • 什么是深拷贝、浅拷贝? 通俗解释:深拷贝是内容拷贝,浅拷贝是地址拷贝 区别点: 深拷贝会创建一个新的内存空间,拷贝...
    Leafly阅读 11,687评论 1 0
  • 深拷贝,浅拷贝概念 深拷贝就是把原来的数据拷贝出来存到一块新的内存中,并有一个新的指针指向新的内存,拷贝结束之后,...
    f2503bba4cfa阅读 920评论 0 2
  • 深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题。尤其对于初学者来说,我...
    西门淋雨阅读 1,829评论 0 1
  • 其实我不懂,怎么扮演好我生命中属于我的每一个角色,我不知道该怎么对待我身边的每一个人,无论关系远近,我都不知道该怎...
    术谨阅读 239评论 0 0