iOS 深拷贝与浅拷贝

本文参考

博文配图
容器类和非容器类
  1. 容器类:数组、字典、集合等。

    • 容器类不可变对象: 比如NSArray
    • 容器类可变对象: 比如NSMutableArray
  2. 非容器类:字符串

    • 非容器类不可变对象,比如NSString
    • 非容器类可变对象:比如NSMutableString

初步解释
  1. 非容器类。

    • 浅拷贝:拷贝地址(对非容器类的浅拷贝就是拷贝对象的地址,对象里面存的内容仍然是一份,没有新的内存被分配。)
    • 深拷贝:拷贝内容(对非容器类的深拷贝就是重新分配一块内存,然后把另一个对象的内容原封不动的给我拿过来。)
  2. 容器类

    • 浅拷贝:生成一个新的容器(也就是“壳”),但是里面保存的元素的指针还是指向原来的元素地址。也就是说,对于容器类的浅拷贝来说,容器的地址是不同的,但是里面的内容地址是相同的,修改其中一个的内容,会使另一个的也跟着变化。(容器类的浅拷贝是对容器里的内容不进行拷贝,两个容器的地址是不同的,但容器里的所装的东西是一样的,在一个容器中修改值,则另一个浅拷贝的容器中的值也会变化。)
    • 深拷贝:不光生成一个新的容器,对容器里面的元素也进行拷贝。
image

immutableObject、mutableObject

immutableObject,不可变对象如:NSString,NSArray等
mutableObject,可变对象例如:NSMutableString,NSMutableArray等


copy 和 mutablecopy

****copy 和 mutablecopy主要是为了生成对象的副本来使用****。

  • copy:copy出来的对象类型总是不可变的(例如, NSString, NSDictionary, NSArray等等)。

  • mutablecopy:mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)

注意:产生一个对象的可变副本并不要求被复制的对象是可变的,同理,可变对象也可以创建一个不可变副本。也就是说,mutableCooy和copy对于不可变对象和可变对象都可以使用。

1.对于非容器类(非集合类)对象
  • 对于不可变对象(immutableObject)

    • copy,浅拷贝(指针拷贝)。返回的是一个不可变类型的对象。(只有这一个是浅拷贝,不可变对象的copy)
    • mutableCopy,深拷贝(内容拷贝)。返回的是一个可变类型的对象。
  • 对于可变对象(mutableObject)

    • copy,深拷贝(内容拷贝)。返回的是一个不可变类型的对象。
    • mutableCopy,深拷贝(内容拷贝)。返回的是一个可变类型的对象。
[immutableObject copy]          //浅拷贝
[immutableObject mutableCopy]   //深拷贝
[mutableObject copy]            //深拷贝
[mutableObject mutableCopy]     //深拷贝
2.对于容器类(集合类)对象
  • 对于不可变对象(immutableObject)

    • copy,浅拷贝(指针拷贝)。返回的是一个不可变类型的对象。(只有这一个是浅拷贝,不可变对象的copy)
    • mutableCopy,深拷贝(内容拷贝)。返回的是一个可变类型的对象。
  • 对于可变对象(mutableObject)

    • copy,深拷贝(内容拷贝)。返回的是一个不可变类型的对象。
    • mutableCopy,深拷贝(内容拷贝)。返回的是一个可变类型的对象。

用代码简单表示如下:(注意,容器类的浅拷贝是容器新生成,里面的元素还是指向原来的)

[immutableObject copy]          //浅拷贝
[immutableObject mutableCopy]   //深拷贝
[mutableObject copy]            //深拷贝
[mutableObject mutableCopy]     //深拷贝
strong和copy的代码测试
  • copy只能修饰不可变类型,当修饰可变类型时,编译虽然不会出错,但是copy出来的是一个不可变类型对象,它被赋值给一个可变类型对象,当调用其方法修改其内容时会崩溃。
  • 注意:*NSString,对不可变类型的指针重新赋值,会改变其地址。NSString str = @"xxxxxx";//地址为0x100001050;str = @"ssssss";//地址为0x1000010d0
  • 所以说,如果用strong修饰NSString,赋值的来源是不可变(NSString)的话,即使赋值来源的内容被更改了,也不会影响被赋值的NSString对象;copy也是如此,虽然对于赋值来源是不可变(NSString)的拷贝是浅拷贝,但即使赋值来源的内容改变了,也不会有影响。因为赋值来源会重新指向一个地址,不是在原地址上更改内容。
@interface Kaobei : NSObject
@property (strong,nonatomic) NSString *strStrong;
@property (copy,nonatomic) NSString *strCopy;
@end
@implementation Kaobei

- (void)test{
    
    NSString *str = @"xxxxxx";
    
    self.strStrong = str;
    
    self.strCopy = str;
    
    NSLog(@"str = %p",str);             //str = 0x100001050
    NSLog(@"strStrong = %p",_strStrong);//strStrong = 0x100001050
    NSLog(@"strCopy = %p",_strCopy);    //strCopy = 0x100001050
    
    str = @"ssssss";
    
    NSLog(@"str = %p",str);             //str = 0x1000010d0
    NSLog(@"strStrong = %p",_strStrong);//strStrong = 0x100001050
    NSLog(@"strCopy = %p",_strCopy);    //strCopy = 0x100001050

}

@end

使用copy而不用strong的原因

因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.

关于retain和copy、mutableCopy的异同点
  1. retain:始终是浅拷贝。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。

  2. copy:对于可变对象为深拷贝,引用计数不改变对于不可变对象是浅拷贝,引用计数每次加一。始终返回一个不可变对象。

  3. mutableCopy:始终是深拷贝,引用计数不改变。始终返回一个可变对象。

自定义类对象之间的深浅拷贝问题

在Objective-C中并不是所有的类都支持拷贝;只有遵循NSCopying协议的类,才支持copy拷贝,只有遵循NSMutableCopying协议的类,才支持mutableCopy拷贝。如果没有遵循拷贝协议,拷贝时会出错。

如果我们想再我们自定义的类中支持copy和mutableCopy那么我们就需要使我们定义的类遵循NSCopying和NSMutableCopying协议,代码如下:

@interface Test : NSObject <NSCopying, NSMutableCopying>

然后再重写-(id) copyWithZone : (NSZone *) zone 和 -(id)mutableCopyWithZone : (NSZone *) zone

重写-(id) copyWithZone :(NSZone *)zone方法如下

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

推荐阅读更多精彩内容

  • 1、对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针;深复制是直接...
    滴答大阅读 743评论 0 2
  • 1、浅拷贝: 拷贝了指向对象的指针,并没有复制对象本身,两个指针指向同一片地址空间. 2、深拷贝:重新复制了一个新...
    一滴矿泉水阅读 445评论 0 1
  • 首先提出一个问题 @property声明的NSString(或NSArray,NSDictionary),为什么经...
    hanzhansen阅读 434评论 0 4
  • 深拷贝和浅拷贝苹果官网上的解释如下: There are two kinds of object copying:...
    FlyElephant阅读 600评论 1 4
  • 大家好,我是西瓜,现居广州。在今年想要回顾梳理一下OC的相关知识点。今天就先从基础但不简单的深拷贝与浅拷贝开始吧。...
    watermelon_lp阅读 389评论 0 5