iOS 拷贝

学习资料
首先iOS拷贝可以区分为 深拷贝浅拷贝
浅拷贝:拷贝了对象的指针,可以理解为给一条狗加了一条绳子。
深拷贝 :直接拷贝对象到另外一块内存地址中,可以理解为新买了一条狗。

  • 深浅拷贝取决于拷贝后的对象是不是和被拷贝对象的地址相同,如果不同,则产生了新的对象,即为深拷贝。如果相同,则只是指针拷贝,相当于retain一次原对象,即为浅拷贝。
  • copymutableCopy和是不是深拷贝没有关系,我们判断是不是深拷贝,仅仅是判断拷贝之后的对象和原对象是不是内存地址相同。不相同的话就是深拷贝,相同就是浅拷贝。

为什么定义字符串属性的时候要用 copy

一个不可变字符串和一个可变字符串指向同一块地址的时候,修改可变字符串,不可变字符串也跟着变化了。

NSString *name1 = @"";
// self.name1 == , 0x100a34118
NSLog(@"self.name1 == %@, %p",name1, name1); 

NSMutableString *strMu = @"dd".mutableCopy;
// mutable == dd, 0x281f09860
NSLog(@"mutable == %@, %p",strMu, strMu);

name1 = strMu;
// self.name2 == dd, 0x281f09860
NSLog(@"self.name2 == %@, %p",name1, name1);

[strMu appendString:@"mm"];
// self.name3 == ddmm, 0x281f09860
NSLog(@"self.name3 == %@, %p",name1, name1);    

NSObject提供了copymutableCopy 方法,copy复制后对象是不可变对象(immutable),mutableCopy复制后的对象是可变对象(mutable),与原始对象是否可变无关。

对非集合类对象 copy 和 mutableCopy

  • 对不可变对象执行copy操作,是指针复制<浅拷贝>,执行mutableCopy操作是内容复制<深拷贝>。
  • 对可变对象执行copy操作和mutableCopy操作都是内容复制<深拷贝>。

[immutableObject copy]; // 浅复制
[immutableObject mutableCopy]; // 深复制
[mutableObject copy]; // 深复制
[mutableObject mutableCopy]; // 深复制

集合类对象的 copy 和 mutableCopy

  • 对于集合类对象的拷贝,我们探讨的是内部元素对应的地址是不是变化,而不是集合本身的地址是否变化了。
集合浅拷贝
NSMutableString *red = @"red".mutableCopy;
NSMutableString *green = @"green".mutableCopy;
NSMutableString *blue = @"blue".mutableCopy;

NSArray *arrOrigin = @[red, green, blue];
NSMutableArray *arrMu1 = arrOrigin.mutableCopy;
NSLog(@"origin == %p",arrOrigin);
NSLog(@"mut == %p",arrMu1);

NSMutableString *strMu = arrMu1.firstObject;
NSLog(@"red == %p",red);
NSLog(@"strMu == %p",strMu);

打印结果为:
originArr == 0x28297bcc0
mutArr == 0x28297ba80

red == 0x28297b1b0
strMu == 0x28297b1b0

虽然集合的地址变化了,但是内部元素的地址没有变,所以是浅拷贝。

集合深拷贝

有两种方式对容器类对象进行深复制:

  • 第一种方法是:使用initWithArray: copyItems:类型方法,其中,第二个参数为YES。
  • 第二种方法是:使用归档、解档。

方式一:initWithArray: copyItems:
下面先看如何使用initWithArray: copyItems:类型方法。使用该方法进行深复制时,第二个参数为YES。如果使用该方法对集合进行深复制,那么集合内每个元素都会收到copyWithZone:消息,我们平常使用copy、mutableCopy方法时,系统会把copymutableCopy自动替换为copyWithZone:mutableCopyWithZone:。即copymutableCopy只是简便方法。如果集合内元素遵守NSCopying协议,元素被复制到新的集合。如果集合内元素不遵守NSCopying协议,用这样的方式进行深复制,会在运行时产生错误。

copyWithZone:产生的是浅复制,所以,这种方法只能产生一层深复制 one-level-deep copy,如果集合内元素仍然是集合,则子集合内元素不会被深复制,只对子集合内元素指针进行复制。

如果集合内元素为不可变对象,发送copyWithZone:消息后进行指针复制,该对象仍然不可变,因此只进行了指针复制。
如果集合内元素为可变对象,发送copyWithZone:消息后进行的是内容复制,复制后该元素不可变,此时,完成了一层深复制。

NSMutableString *red = @"red".mutableCopy;
NSMutableString *green = @"green".mutableCopy;
NSString *blue = @"blue";

NSArray *arrOrigin = @[red, green, blue];
NSMutableArray *arrMu1 = arrOrigin.mutableCopy;
NSMutableArray *arrDeep = [NSMutableArray.alloc initWithArray:arrOrigin copyItems:true];

NSMutableString *strMuFirst = arrMu1.firstObject;
NSMutableString *strDeepFirst = arrDeep.firstObject;
NSLog(@"red == %p",red);
NSLog(@"strMuFirst == %p",strMuFirst);
NSLog(@"strDeepFirst == %p",strDeepFirst);
NSLog(@"\n");
NSMutableString *strMu = arrMu1.lastObject;
NSMutableString *strDeep = arrDeep.lastObject;
NSLog(@"blue == %p",blue);
NSLog(@"strMu == %p",strMu);
NSLog(@"strDeep == %p",strDeep);

/// 此时元素是可变元素,此时进行了深拷贝
red == 0x2821c6cd0
strMuFirst == 0x2821c6cd0
strDeepFirst == 0xf3a8558d022e8484
 
/// 这个元素是不可变元素,此时进行了浅拷贝
blue == 0x100634288
strMu == 0x100634288
strDeep == 0x100634288

方式二 归档、解档

// 5.使用归档进行完全深复制。
- (void)trueDeepCopy {
    // 1.创建一个可变数组,数组第一个元素是另一个可变数组,第二个元素是另一个不可变数组。
    NSMutableString *hue = [NSMutableString stringWithString:@"hue"];
    NSMutableString *saturation = [NSMutableString stringWithString:@"saturation"];
    NSMutableString *brightness = [NSMutableString stringWithString:@"brightness"];
    NSMutableArray *hsbArray1 = [NSMutableArray arrayWithObjects:hue, saturation, brightness, nil];
    NSArray *hsbArray2 = [NSArray arrayWithObjects:hue, saturation, brightness, nil];
    NSMutableArray *hsbArray3 = [NSMutableArray arrayWithObjects:hsbArray1, hsbArray2, nil];
    
    // 2.通过归档、解档进行完全深复制。
    NSData *dataArea = [NSKeyedArchiver archivedDataWithRootObject:hsbArray3];
    NSMutableArray *hsbArray4 = [NSKeyedUnarchiver unarchiveObjectWithData:dataArea];
    
    // 3.输出hsbArray3和hsbArray4数组第一个元素内存地址。
    NSLog(@"Memory location of \n hsbArray3.firstObject = %p, \n hsbArray4.firstObject = %p",hsbArray3.firstObject, hsbArray4.firstObject);
打印结果:
Memory location of 
 hsbArray3.firstObject = 0x60000004b100, 
 hsbArray4.firstObject = 0x60000004b1f0
}

内存地址不一样,进行了深拷贝。

自定义对象的拷贝
自定义对象的拷贝,需要实现NSCoping或者NSMutableCoping协议。

@interface Person()<NSCopying>
@end

@implementation Person

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

推荐阅读更多精彩内容

  • 1、什么是深拷贝什么是浅拷贝?浅拷贝和深拷贝的区别 * 浅拷贝(shallow copy):指针拷贝,对于被拷贝对...
    mayuee阅读 213评论 0 2
  • iOS 拷贝问题 之前在孙**同学面试过程中,发现一些自己对深浅拷贝、可变不可变拷贝的理解有问题,后来在网上也发现...
    白公子是猫奴阅读 440评论 0 0
  • 首先说明两个概念 容器类对象:系统的容器类对象,指NSArray,NSDictionary等 非容器类对象:系统的...
    mayuee阅读 339评论 0 0
  • 深拷贝 深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。 浅拷贝 浅拷贝:只...
    雨洒潇湘阅读 427评论 0 1
  • copy和mutableCopy的概念: copy浅拷贝,不拷贝对象本身,仅仅是拷贝指向对象的指针。 mutabl...
    顶级蜗牛阅读 2,087评论 1 3