深拷贝浅拷贝

参考链接:

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操作都创建了一个新的不可变字符串,不会发生问题。

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

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