理解本质,mutableCopy和copy的一切问题,引刃而解

内容均为原创, 如有任何疑问或者错误,请在文章下留言或者直接与我联系,一定及时回复: )
对于copymutableCopy这两个方法,相信大家在日常开发中并不陌生,但是有一部分程序员对于这两者的认知,仅仅停留在copy是浅拷贝,mutableCopy是深拷贝,NSString需要用copy修饰,不然会出问题,具体出什么问题,也说不上来。本文将从苹果的API文档入手,对copymutablecopy做由浅入深的剖析。
主要说明以下问题:
---- 可变拷贝&不可变拷贝,深拷贝&浅拷贝。
---- copy一定是浅拷贝,mutableCopy一定是深拷贝吗?
---- NSString作为属性时,一定要用copy修饰吗?如果不用copy,会发生什么状况?

0.什么是拷贝?

在我们平时的电脑使用中,当需要对一个文件做修改,但是没有100%的把握可以按照需求修改好,或者修改后还是需要留一份修改前的文件,这个时候我们会用到拷贝操作。如下图。

image.png

简单来说就是副本文件和原文件之间的数据修改,互不影响。这就是拷贝这个操作真正的意义。

1.可变拷贝&不可变拷贝,深拷贝&浅拷贝。

我们都知道,foundation框架中提供给我们的部分类比如NSString,NSArray有可变和不可变之分;对于这些实现了NSCopy协议的类,执行不可变拷贝操作,会调用其协议方法- (id)mutableCopyWithZone:(NSZone *)zone;,返回一个不可变的对象。可变拷贝,会调用其协议方法- (id)copyWithZone:(NSZone *)zone;,返回一个可变的对象。如果拷贝操作返回的是一个新的对象,那么我们就称其为深拷贝;返回结果没有产生新对象,我们称其为浅拷贝。
所以,深浅拷贝是对拷贝结果的一个简称,copy不等于浅拷贝,mutableCopy不等于深拷贝。

2.copy一定是浅拷贝,mutableCopy一定是深拷贝吗?

首先,我们来看下对不可变对象进行copy操作会发生什么情况:
NSString *test = @"test";
NSString *test2 = [test copy];
NSLog(@"%p,%p",test,test2);
2018-10-04 00:38:29.360235+0800 gcdtestr[32886:1486529] 0x104768260,0x104768260

通过内存地址,我们可以发现,对一个不可变的常量字符串进行copy操作,并没有返回一个全新的对象,而是简单的指针复制(浅拷贝)。

对可变对象进行copy:
NSMutableString *test = [NSMutableString stringWithFormat:@"test"];
NSString *test2 = [test copy];
NSLog(@"%p,%p",test,test2);
2018-10-04 00:41:58.144299+0800 gcdtestr[32934:1490919] 0x6000015642d0,0xfad0108fd523415a

通过内存地址,我们可以发现,对一个可变字符串进行copy操作,得到了一个全新的对象(深拷贝)。

通过打印结果,我们知道了copy和mutableCopy的区别是前者不会产生新的对象,后者会产生新的对象这句话是错误的。在对不可变对象进行copy的操作,会返回给我们一个全新的、不可变的对象。

2.1为什么对可变对象copy会返回一个不可变的对象,而不是简单地复制指针呢?

有两个原因,第一:copy本来就是不可变拷贝,所以对不可变对象进行拷贝的时候,只能返回一个新的不可变对象。第二:要从拷贝这个操作发明的初衷去理解了,我们之所以需要拷贝,是希望副本和原文件两者都是独立存在且互不影响的,如果对不可变对象仅仅做一个指针复制的操作,由于两者都指向同一块内存,对副本进行修改的时候,会影响到到原对象,那么这就违背了我们拷贝的初衷了。

2.2 为什么对不可变对象copy,仅仅复制指针,而不是创建一个新的不可变对象?

原因很简单,因为不可变对象它被创建出来后就再也无法被修改了,连修改都不能了,更不存在修改副本对象影响到原对象了,所以副本和原对象指向同一块内存不会产生问题,不需要浪费内存创建一个新的对象。

2.3 mutableCopy一定是深拷贝吗?

mutableCopy一定是深拷贝。这个问题其实不用代码演示,理解了拷贝操作的原理,我们就可以推测到当我们对可变对象进行mutableCopy的时候,由于是可变拷贝,需要返回一个可变的对象,副本对象和原对象都是可变的,那不可能两个指针都指向同一块内存(2.1中已经说明)。对不可变对象进行可变拷贝那就更需要返回一个新对象了。

3.NSString作为属性时,一定要用copy修饰吗?如果不用copy,会发生什么状况?

@property (nonatomic, copy) NSString *testStr;

当我们用copy修饰符号修饰属性时,runtime会在赋值前调用一次copy方法,set方法大概长这样:

-(void)setTestStr:(NSString *)testStr{
    _testStr = [testStr copy];
}

通过set方法的代码,我们可以发现:如果给testStr属性赋值一个不可变的字符串,那么无论用copy和strong修饰,都不会产生任何问题。原因上面已经说了,不可变的字符串调用copy方法,仅仅是指针复制而已,和strong的效果一模一样。
但是如果我给testStr属性赋值一个可变的字符串,strong和copy修饰的差别就体现出来了。用copy修饰,赋值时会进行一个copy操作,产生一个全新的不可变对象,副本和原对象互不影响。也就是说赋值完毕后,testStr属性已经给自己保留了一份副本,不管原字符串如何修改,都不会影响到testStr属性的值。strong修饰,则不会产生副本,当传入的可变字符串在其他地方被修改了,testStr属性的值也会一起被修改!试想一下如果UITextField控件苹果用strong对其text属性修饰,那么当你给其赋值一个NSMutableString类型的对象后,将来这个MutableString的值一旦被修改,UITextField的值也会一起被修改,用户会懵逼的,明明什么都没做,怎么刚刚输入的内容,就被修改了呢!?

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

推荐阅读更多精彩内容