OC中与copy有关的那些事 一 (copy与声明NSString属性 : strong/copy 的关系)
来源:互联网 发布:招聘网络平面设计师 编辑:程序博客网 时间:2024/05/18 13:04
前言:
最近有时间,想要把oc的基础知识重新梳理巩固一遍,在学习当中又有了新的理解,自己总结之后记录一下,以免过后又糊涂。。。首先就从copy相关的内容下手吧!
第1节、深拷贝与浅拷贝
谈到copy,肯定要聊到OC的深拷贝与浅拷贝(又称为内存拷贝与指针拷贝)。这也是面试时面试官经常会问起的题目。关于深拷贝与浅拷贝,网上已经有很多优秀的文章探讨过了,但因为这篇的内容跟深、浅拷贝有一定关系,还是说明一下。
首先明确一点: copy出的对象为imutable(不可变)类型,mutableCopy出的对象为mutable(可变)类型
对于NSString:copy/mutableCopy
NSString *origanlStr = [NSString stringWithFormat:@"abc"]; //没产生新内存空间 NSString *copyStr = [origanlStr copy]; //产生了新内存空间 NSMutableString *mutableStr = [origanlStr mutableCopy]; NSLog(@"---origanlStr is %@, %p", origanlStr, origanlStr); NSLog(@"---copyStr is %@, %p", copyStr, copyStr); NSLog(@"---mutableStr is %@, %p", mutableStr, mutableStr);
打印结果为:
2017-02-21 16:15:39.606 TestProiect[56256:3824325] ---origanlStr is abc, 0xa0000000063626132017-02-21 16:15:39.607 TestProiect[56256:3824325] ---copyStr is abc, 0xa0000000063626132017-02-21 16:15:39.607 TestProiect[56256:3824325] ---mutableStr is abc, 0x60000006a140
可以看到:对NSString对象来说,copy不会产生新对象,mutableCopy会产生新的NSMutableString对象。
对于NSMutableString:copy/mutableCopy
NSMutableString *origanlStr = [NSMutableString stringWithFormat:@"abc"]; //产生了新内存空间 NSString *copyStr = [origanlStr copy]; //产生了新内存空间 NSMutableString *mutableStr = [origanlStr mutableCopy]; NSLog(@"---origanlStr is %@, %p", origanlStr, origanlStr); NSLog(@"---copyStr is %@, %p", copyStr, copyStr); NSLog(@"---mutableStr is %@, %p", mutableStr, mutableStr);
打印结果为:
2017-02-21 16:26:28.484 TestProiect[56276:3831735] ---origanlStr is abc, 0x6100002610802017-02-21 16:26:28.484 TestProiect[56276:3831735] ---copyStr is abc, 0xa0000000063626132017-02-21 16:26:28.484 TestProiect[56276:3831735] ---mutableStr is abc, 0x6100002610c0
可以看到:对NSMutableString对象来说,copy和mutableCopy会产生新的对象。
这样我们可以得到结论如下图:
在上面的这幅图中,我们把结论扩展到了NSArray和其他的NS对象。但注意,对于NSArray、NSDictionary这类的容器对象(也就是可以容纳其他元素的对象)来做copy或mutableCopy时,对NSArray、NSDictionary类型的对象本身来说是满足上面表里的原则的,也就是与NSString类似。但对于这些容器内部的元素来说,只会进行指针拷贝,并不会为其开辟出新的内存空间。
对于其他的NS对象,则必须满足NSCopying和NSMutableCopying协议才能执行copy或mutableCopy消息,否则会导致程序崩溃。
对于容器类的深浅拷贝,由于需要考虑较多,本篇先不做过多说明,之后会开一篇新的博客解释。
第2节、用strong还是用copy?
了解完了深浅拷贝的基本使用,下面进入正题:在声明NSString类型的属性时大家都知道要用copy来修饰。但是具体是为什么呢?下面就详细的分析一下。
①:我们首先用strong和copy分别修饰NSString类型的属性:
@property (nonatomic, copy) NSString *myCopyStr;@property (nonatomic, strong) NSString *myStrongStr;
NSString *origanlStr = [NSString stringWithFormat:@"abc"]; self.myCopyStr = origanlStr; self.myStrongStr = origanlStr; origanlStr = @"456"; NSLog(@"---origanlStr is %@, %p", origanlStr, origanlStr); NSLog(@"---myCopyStr is %@, %p", self.myCopyStr, self.myCopyStr); NSLog(@"---myStrongStr is %@, %p", self.myStrongStr, self.myStrongStr);
打印出的结果是这样的:
2017-02-21 17:04:03.336 TestProiect[56347:3867212] ---origanlStr is 456, 0x10ecbde902017-02-21 17:04:03.336 TestProiect[56347:3867212] ---myCopyStr is abc, 0xa0000000063626132017-02-21 17:04:03.337 TestProiect[56347:3867212] ---myStrongStr is abc, 0xa000000006362613
看起来用strong和copy修饰的NSString类型属性表现完全一样嘛。。。那为什么还要区分用strong和copy修饰呢?
②:那我们再看下面的代码:
NSMutableString *origanlStr = [NSMutableString stringWithFormat:@"abc"]; self.myCopyStr = origanlStr; self.myStrongStr = origanlStr; [origanlStr appendString:@"456"]; NSLog(@"---origanlStr is %@, %p", origanlStr, origanlStr); NSLog(@"---myCopyStr is %@, %p", self.myCopyStr, self.myCopyStr); NSLog(@"---myStrongStr is %@, %p", self.myStrongStr, self.myStrongStr);
在这段代码里,我们把元字符串origanlStr变为了NSMutableString类型,并且在后面改变了origanlStr的值(在原先的”abc”后面拼接了”456”)。
这样打印出来的结果为:
2017-02-21 17:12:13.722 TestProiect[56370:3876839] ---origanlStr is abc456, 0x6000000741002017-02-21 17:12:13.723 TestProiect[56370:3876839] ---myCopyStr is abc, 0xa0000000063626132017-02-21 17:12:13.723 TestProiect[56370:3876839] ---myStrongStr is abc456, 0x600000074100
这样就看出区别了吧,如果是用copy类型声明的NSString类型属性,如果元字符串为可变类型,在元字符串值改变之后,因为其内存地址与元字符串内存地址不一致,其属性值不会随之改变。
而如果是用strong类型声明的NSString类型属性,如果元字符串为可变类型,在元字符串值改变之后,因为其内存地址与元字符串内存地址一样,其属性值也会随之改变。
为什么元字符串是可变或者不可变,会导致这样不同的结果呢?
这是因为如果元字符串为不可变类型(NSString)时:
这些不可变对象是分配在静态存储区的,整个进程公用一份对象,所以无论是strong或copy声明属性,指向的存储空间都是同一个,所以没有区别。又因为元字符串为不可变类型,所以它的值不会变,因此无论是strong或copy声明属性,它们的值也不会变。由此我们得出结论:如果元字符串为不可变类型时,声明属性为strong或copy都一样。
如果元字符串为可变类型(NSMutableString)时:
对于用strong声明的属性,将元字符串赋值给它时,只是将其引用计数器+1,属性指向的内存与元字符串指针指向的内存都为同一块。所以当元字符串改变内存里的值时(拼接了”456”),该属性的值也会随之改变。
对于用copy声明的属性,将元字符串赋值给它时,实际上是将元字符串进行copy。由第一节的结论可知,当元字符串为可变类型时,对其copy是进行了深拷贝。为这个属性开辟了一个新的内存空间,将元字符串的值copy过去。所以这个属性的值不会随元字符串的值改变而改变。
由此我们得出结论:如果元字符串为可变类型时,声明属性为strong的值会随着元字符串改变;声明属性为copy的值不会随着元字符串改变。
一般我们声明NSString类型属性时,都不会希望属性值随着元字符串值改变。所以通常情况下就用copy声明啦。。。
注意:
在上面的分析中,可能会同学有如下疑问:
NSString *origanlStr = [NSString stringWithFormat:@"abc"]; self.myCopyStr = origanlStr; self.myStrongStr = origanlStr; origanlStr = @"456"; NSLog(@"---origanlStr is %@, %p", origanlStr, origanlStr); NSLog(@"---myCopyStr is %@, %p", self.myCopyStr, self.myCopyStr); NSLog(@"---myStrongStr is %@, %p", self.myStrongStr, self.myStrongStr);
当元字符串为不可变类型(NSString)时,无论是strong或copy声明属性,指向的内存空间都是同一个。当origanlStr变为”456”时,为什么strong或copy属性的值没有随着变化呢?
这是因为当origanlStr变为”456”时,其实是将origanlStr由指向原先”abc”的内存空间重新指向了新的”456”内存空间。但是原先 self.myCopyStr和 self.myStrongStr指向的”abc”的内存空间并没有变化。
举个栗子:两把钥匙A(origanlStr)、B(self.myCopyStr),B复制A后(self.myCopyStr = origanlStr),AB钥匙都可以开(指向)同一把锁(”abc”),后来A重新被磨了(赋值)新的一把钥匙,能开别的锁了(origanlStr = @”456”),但并不能改变B(self.myCopyStr的值仍然为”abc”)。
第3节、copy与属性的关系
上面说了这么多,我们快要接近属性声明copy/strong的本质了。
实际上,当我们声明一个属性为copy时实际上是这样的:
@property (nonatomic, copy) NSString *myCopyStr;
-(void)setMyCopyStr:(NSString *)myCopyStr { _myCopyStr = [myCopyStr copy];}
是的,在我们声明为copy之后,系统会自动在set方法中执行这个属性的copy方法。这样就实现了这个属性的copy特性,就可以保证它的值不会随着元字符串值的改变而改变啦!
相对的,当我们声明一个属性为strong时实际上是这样的:
@property (nonatomic, strong) NSString *myStrongStr;
-(void)setMyStrongStr:(NSString *)myStrongStr { _myStrongStr = myStrongStr;}
可以看到,在我们声明为strong之后,系统只是单纯的引用一下,让其引用计数器+1,所以它的值会随着元字符串值的改变而改变。
假设属性改为NSMutableString,会发生什么事?
@property (nonatomic, copy) NSMutableString *myMutableCopyStr;
这样的话它的set方法还是这样:
-(void)setMyMutableCopyStr:(NSMutableString *)myMutableCopyStr { _myMutableCopyStr = [myMutableCopyStr copy];}
copy出来的仍然是不可变字符!如果有人用NSMutableString的方法,就会崩溃:
NSMutableString *origanlStr = [NSMutableString stringWithFormat:@"abc"]; self.myMutableCopyStr = origanlStr; [self.myMutableCopyStr appendString:@"haha"];
参考来源:
iOS 浅谈:深.浅拷贝与copy.strong
Copying Collections
- OC中与copy有关的那些事 一 (copy与声明NSString属性 : strong/copy 的关系)
- 声明NSString属性用 Copy 与 strong 的区别
- 使用copy与strong声明NSString属性的区别
- NSString的strong和copy
- NSString的copy 属性
- NSString 的copy 与 mutableCopy
- 由NSString的copy和strong/retain引出o-c的copy机制 (一)
- OC的copy与mutableCopy剖析(copy篇)
- 关于NSString中的copy与strong
- 初探 属性的copy、strong
- NSString类型copy和strong属性的区别
- iOS学习——NSString属性的strong和copy
- NSString应用copy和strong的区别
- NSString 的copy和strong浅析
- iOS-修饰NSString的strong和copy
- strong和copy对NSString的影响
- 关于声明属性Strong还是Copy的用法
- NSString中使用copy 和 strong的区别?
- 51单片机之声双色点阵驱动
- RESTful
- 设计模式——代理模式
- 263. Ugly Number
- [容斥原理] BZOJ 2839 集合计数
- OC中与copy有关的那些事 一 (copy与声明NSString属性 : strong/copy 的关系)
- 广告行业eCPM概念
- linux shell 获取当前正在执行脚本的绝对路径
- linux下多线程之生成者与消费者模型(互斥,读写锁,条件变量)
- onCreateContextMenu用法
- 接口三
- swift3.0 基本数据类型
- 【老戴说镜头】怎样才算一颗好的镜头
- apache日志分析简介