iOS内存管理系列2之 copy和strong修饰数组及字符串对象的本质区别探究

我觉得我这个人什么都好,就是有时候有点懒 ,搞了三年多iOS开发了,回头一看网上都没有留下自己的痕迹,昨天跟一位CTO聊天,讲到职业发展的道路,他跟我说,作为一个技术人员,要懂得分享,要学会传播自己的知识,而不能掖着藏着,你在分享的过程中,不仅自己对知识的理解更到位,还能扩大自己在圈子里的影响力,走上更好的职业发展之路,听完他的话,我觉得我浪费了几年美好的光阴,所以我决定慢慢的把自己懂得东西分享出来,跟大家一起交流一起进步,如果有讲的不好的地方,希望大家多多斧正。
下面进入今天的主题,一直以来不断的有人问我关于内存管理方面的内容,我也回答了很多,今天我就将内存管理方面的一些重要的东西拆成小的模块逐一的讲解下,今天要讲的是字符串里面为什么要用copy来修饰。 请看下面的代码截图:我定义了四个属性,分别用strong来修饰的NSString和用copy来修饰的NSString,这样会形成一个对比,方便大家理解

   @property(nonatomic, strong)NSString *testString;

   @property(nonatomic, strong)NSMutableString *test2String;

   @property(nonatomic, copy)NSString *test3String;

   @property(nonatomic, strong)NSMutableString *test4String;

定义好属性后我们对其进行赋值操作 :

    self.testString = @"aaaa";
    self.test2String  = [[NSMutableString alloc] init];
    self.test2String.string = @"nuli";
    self.testString = _test2String;

    self.test3String = @"bbb";
    NSMutableString *test4String  = [[NSMutableString alloc] init];
    self.test4String = test4String;
    self.test4String.string = [@"fendou" mutableCopy];
    self.test3String = _test4String;

我们首先给testString进行了赋值,然后生成了一个test2String,并对其赋值,然后分别再来看testString和test2String的内存地址和值,我们通过打断点使用lldb来查看,当程序执行到断点处的时候

1.png

![2.png](http://upload-images.jianshu.io/upload_images/4316454-ec471757b6404b7b.png? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

当我们将test2String赋值给testString之后内存地址和值如下图所示:
可以看到两个字符串的值和内存一样,这个时候我们来改变test2String字符串的值然后在来查看:

5.png

我们会发现两个字符串的值同时发生了改变,但内存地址是一致的,所以我们可以肯定两个字符串是共用的一份内存,也就是说使用strong来修饰NSString,在你对其进行赋值的时候,只是复制了一个指针而已,并没有分配新的内存空间,这样的话会导致一个什么样的问题呢?就是你在程序的其他地方更改了test2String的值后testString的值也会发生改变,所以这个会存在潜在的数据污染的风险,如非明确共用一份内存外,不建议使用strong来修饰NSString
下面我们来看看使用copy修饰的字符串赋值的时候是怎么样的,请看下图:当程序执行到这个地方的时候:

7.png
8.png

将test4String的值赋给test3String之后内存地址和值如下图所示:

10.png

可以看到test3String字符串的内存和内容都没有发生改变,改变test3String 的值test4String的地址和内容也没有发生任何改变,所有我们可以知道使用copy关键字修饰的字符串在赋值的时候会重新生成一块新的内存,然后把另一个字符串的内容复制进来,这就相当于两个字符串都存在于两个独立的内存空间,所以改变任何一个字符串的值对另外一个字符串都不会有任何的影响,这个也就是我们所说的深复制。

修饰数组时其实也一样,如下面,我定义了两个可变数组:

@property(nonatomic,copy,nullable)NSMutableArray<YCCombineModel *> *historyOrderArray;

- (void)viewDidLoad {
    [super viewDidLoad];
   NSMutableArray  *arr = [NSMutableArray array];
  _historyOrderArray = a;
    for (int i = 0; i<20; i++) {
        YCCombineModel *model = [[YCCombineModel alloc] init];
        model.isSelected = NO;
        [_historyOrderArray addObject:model];
    }
}

当我用copy修饰数组的时候,代码执行到

 [_historyOrderArray addObject:model];

这行代码的时候会挂掉,要理解崩溃的原因先要知道一些常识性的东西:
在iOS开发中,对象之间传值都是使用引用计数器增加的方式,这种方式的适用于当对象的某属性的值改变时,引用该对象的不同指针会同时改变,因为这两个指针指向的是同一个内存地址,当一个指针执行的对象属性值发生改变时,不影响另一个对象,那么需要分配两个不同的内存地址,也就是说,我们就不可以采用retain关键字了,而是要采用copy 关键字。如:
property (nonatomic,copy)NSSting * name;
一:
区分深复制与浅复制,一般只有可变的mutableCopy到mutableCopy的Copy才是浅复制,不产生副本只是retain count增加。
副本的特点:彼此的内容一样,拥有相同的方法,在内存中有两个对象.
1.copy
1> 如果对象有 可变/不可变 版本的区别, copy方法只能拷贝出不可变的副本.
2> 如果对象没有 可变/不可变 版本的区别,copy方法只是建立一个副本.

2.mutableCopy
建立对象的可变版本的副本(如果对象有 可变/不可变 版本之分)

3.深拷贝/浅拷贝
1>深拷贝:如果建立出新的副本,在内存中有两个对象.就是深拷贝.
可变 -> 不可变 (copy)
可变 -> 可变 (mutableCopy)
不可变 -> 可变 (mutableCopy)

2.浅拷贝:不会建立新的副本, 只是引用计数加1.
不可变 -> 不可变 (因为两个不可变对象谁都不会被改变,也就没必要建立副本)

因为定义了copy修饰属性后 在执行其setter方法的时候会先release掉旧值然后retain 新值,并且上面那种赋值实际就相当于 _historyOrderArray = [arr copy]; copy后就会返回一个NSArray类型的对象。所以调用addObject方法就会报unrecognized selector sent to instance 0x14e14970错误, 但是如果使用strong来修饰_historyOrderArray就相当于直接赋值,不会报错。
看完两个的对比之后,我相信你对字符串和数组的修饰符的使用有了一个新的认识。感谢您花费宝贵的时间来阅读此文!如果有错误的话欢迎大家多多指点,当然有想深入交流的也可以加我微信:bubiandeai05

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

推荐阅读更多精彩内容