深浅拷贝

实例化的对象存储在堆区,而指向对象的指针一般存储在栈区。实际上拷贝分为深拷贝(one level deep copy),浅拷贝(shallow copy)和完全拷贝(real deep copy)三种。

  • 浅拷贝:在操作中,对于被复制对象的每一层都是指针复制。


  • 深拷贝:在操作中,对于被复制对象,至少有一层是深复制。


  • 完全拷贝:在操作中,对于被复制对象,每一层都是对象复制。
image.png

注意

1、深拷贝和完全拷贝

深拷贝,就是把原有对象内容直接克隆一份新的对象,但是这里有一个坑,就是深拷贝只是复制一层对象,而不是复制第二层或者更深层的对象,例如:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM1 = [NSMutableString stringWithString:@"1"];
    NSMutableString *strM2 = [NSMutableString stringWithString:@"2"];
    NSMutableArray *arrM1 = [NSMutableArray arrayWithObjects: strM1, strM2, nil];

   // 深拷贝原数组
    NSMutableArray *arrM2 = [arrM1 mutableCopy];

   // 深拷贝之后,再修改字符“1“ 为 ”11“
    NSMutableString *strM3 = [arrM1 objectAtIndex:0];
    [strM3 appendString:@"1"];

    NSLog(@"strM1--%@",arrM1);
    NSLog(@"strM2--%@",arrM2);
}

看结果:

// 原数组
2017-03-14 00:22:02.260 [5522:393850] strM1--(
    11,
    2
)
// 深拷贝数组
2017-03-14 00:22:02.261 [5522:393850] strM2--(
    11,
    2
)

结论:为什么深拷贝已经复制了对象,那么原对象为什么也同步变化?这里就是深拷贝和完全拷贝的原因,深拷贝只是拷贝了一层数组,但是里面的字符串没有拷贝,两个数组都是用的同一个地址的字符串,所以改变一个,原对象也发生了变化。可以做下面这样的修改。

// copyIitems为YES
NSMutableArray *arrM2 = [[NSMutableArray alloc] initWithArray: arrM1 copyItems:YES];

查看结果

2017-03-14 00:45:45.389 [5916:425450] arrM1--(
    11,
    2
)
2017-03-14 00:45:45.390 [5916:425450] arrM2--(
    1,
    2
)

可以利用这个方法,得到的是多一层的深复制,里面的字符串地址也进行了复制,所以改变strM3的值,不影响arrM1的值。你认为这样就解决了吗?再看下面的问题。

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM1 = [NSMutableString stringWithString:@"1"];
    NSMutableString *strM2 = [NSMutableString stringWithString:@"2"];
    NSMutableArray *arrM1 = [NSMutableArray arrayWithObjects: strM1, strM2, nil];

    // 嵌套了一层数组,arrM1
    NSMutableArray *arrM2 = [NSMutableArray arrayWithObjects: strM1, strM2, arrM1, nil];

    // copyItems会多拷贝一层
    NSMutableArray *arrM3 = [[NSMutableArray alloc] initWithArray:arrM2 copyItems:YES];
     
    // 两层深拷贝后再修改字符串
    NSMutableString *strM3 = [arrM1 objectAtIndex:0];
    [strM3 appendString:@"1"];

    NSLog(@"arrM2--%@",arrM2);
    NSLog(@"arrM3--%@",arrM3);
}

查看结果

2017-03-14 00:55:57.604 [6080:438490] arrM2--(
    11,
    2,
        (
        11,
        2
    )
)
2017-03-14 00:55:57.606 [6080:438490] arrM3--(
   // 第二层没有变化
    1,
    2,
        (
        // 第三层的字符串同步变化了。因为copyItem只是多拷贝了一层
        11,
        2
    )
)

结论:可以发现外层的深复制了,原对象和拷贝后的对象不是同一地址,再往里看一层都变化了,就没有深复制,也就是说再增加一层NSMutableArray *arrM2 = [[NSMutableArray alloc] initWithArray:arrM1 copyItems:YES];这个方法管不了那么多层数。可以采用归档和解档解决该问题:

NSMutableArray *arrM3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arrM2]];

查看结果

2017-03-14 01:17:23.204 [6396:464958] arrM2--(
    11,
    2,
        (
        11,
        2
    )
)
2017-03-14 01:17:23.204 [6396:464958] arrM3--(
    1,
    2,
        (
        1,
        2
    )
)

结论:可以看到实现了完全复制,就没有层数的限制


2、NSString的copy和strong

NSString被copy和strong修饰会有什么不同:

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,copy) NSString *str;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM = [[NSMutableString alloc] initWithString:@"bestDay"];
    self.str = strM;
    [strM appendString:@"OfThisYear"];
    NSLog(@"str----%@---%p",self.str,self.str);
    NSLog(@"strM----%@---%p",strM,strM);

}
@end

直接查看结果

2017-03-14 08:53:01.874 [789:18128] str----bestDay---0xa796144747365627
2017-03-14 08:53:01.875 [789:18128] strM----bestDayOfThisYear---0x600000071280

结论:可以看到copy修饰的str,在赋值以后,可变字符串strM发生了变化并不会影响str的值。从打印结果来看是因为二者不是一个地址,所以不会相互影响。为什么?
是因为copy修饰的属性setter方法,先release旧值,copy新值再赋值给成员变量,不可变copy是深拷贝,就是内容拷贝,地址变化了
接着看strong修饰的情况:

@property (nonatomic,strong) NSString *str;

直接查看结果

2017-03-14 09:03:36.756 [968:29890] str----bestDayOfThisYear---0x6000002600c0
2017-03-14 09:03:36.757 [968:29890] strM----bestDayOfThisYear---0x6000002600c0

结论:被strong修饰以后只是强指针引用,并未改变地址,所以str的值会随着strM进行变化,二者的地址也是相同的。


3、理解copy和retain的不同

在MRC下进行测试,先看代码

//copy和retain的区别
- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableArray *arrM = [NSMutableArray arrayWithObjects:@"111",@"222",@"333", nil];

    NSMutableArray *arrMRetain = [arrM retain];
    NSMutableArray *arrMCopy = [arrM copy];
    [arrM removeLastObject];

    NSLog(@"arrMRetain--%@--%p--%lu",arrMRetain,arrMRetain,[arrMRetain retainCount]);
    NSLog(@"arrMCopy--%@--%p--%lu",arrMCopy,arrMCopy,[arrMCopy retainCount]);

}

查看结

2017-03-14 20:16:59.895 copy和retain的区别[2816:177901] arrMRetain--(
    111,
    222
)--0x60000005cf50--2
2017-03-14 20:16:59.895 [2816:177901] arrMCopy--(
    111,
    222,
    333
)--0x60000005cf80--1

结论:copy是深复制,retainCount为1,retain是浅复制,retain是使原来对象引用计数加1,所以arrM和arrMRetain是同一地址,所以remove最后一个元素,arrMRetain也跟着变化了。

参考

ios中的拷贝你知道多少?

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

推荐阅读更多精彩内容

  • 简述深浅拷贝 我们实例化的对象存储在堆区,而指向对象的指针一般存储在栈区。我们需要知道这个前提。  实际上拷贝分为...
    朽木自雕也阅读 619评论 1 3
  • 道歉 之前我的一篇关于深浅拷贝的文章,里面有诸多错误,主要是混淆了混淆copy、mutableCopy和深浅拷贝,...
    西木柚子阅读 3,118评论 20 46
  • 一、深浅拷贝 1、 什么是深拷贝? 深拷贝是对内容的拷贝,复制内容,同时有新的指针指向该内存区域; 2、什么是浅拷...
    Ching_Han阅读 612评论 0 5
  • Copy的作用 在OC中,copy 是利用一个源对象产生一个副本对象,本质就是当修改源对象的属性和行为,不会影响副...
    骑行怪状阅读 2,363评论 3 5
  • 先秦散文,汉赋,唐诗,宋长短句,元戏剧,明清小说,民国白话文新体诗。我如今清浅的涉猎,愿能成就我实在平凡而逐渐明朗...
    群玉秉辉阅读 276评论 0 1