作者君:经过浏览一些博客所得,方便自己浏览和积累。如有侵权,请联系我!!!
一、strong和copy的区别
首先要知道这两者的区别,我认为应该要知道,oc中的setter和getter方法来由、深拷贝和浅拷贝的原理。
A.setter和getter方法:
a.时间线:
- 在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量
- 在Xcode中间的一个版本中,不再需要为属性声明实例变量了,因为@synthesize默认会去访问str的同名,如果找不到同名变量,会自动生成一个叫做str的私有同名变量。
- 在xcode4.5及以后的版本中,直接把@synthesize给省略
b.在这里说明一下@synthesize的作用:
- 一个作用就是让编译器为你自动生成setter与getter方法。
- 还有一个作用,可以指定与属性对应的实例变量,例如
@synthesize str = xxx;
那么操作的实例变量是xxx,而不是_str了。如果.m文件中写了@synthesize str;
那么生成的实例变量就是str;如果没写@synthesize str;那么生成的实例变量就是_str。(注意:_str这个实例变量是不存在的). 在老式的代码中,@property只能写在@interface @end
中,@synthesize只能写在@implementation @end
中,自从xcode 4.5及以后的版本中,@property就独揽了@property和@synthesize的功能。
@property (nonatomic, copy) NSString *str;
这句话完成了3个功能:
1)生成_str成员变量的getter和setter方法的声明;
2)生成_str成员变量setter和getter方法的实现;
3)生成一个_str的成员变量。(注意:这种方式生成的成员变量是private的)
c.使用方式
点语法:
- 在等号左边即为set方法
- 在等号右边即为get方法
一般方法:
- 使用set方法:[A setName:@""];
- 使用get方法:[A name];
B、深拷贝和浅拷贝
- 如果对象是不可变的,
copy
会进行浅拷贝,mutableCopy
会进行深拷贝 - 如果对象是可变的,那么无论是
copy
还是mutableCopy
都会进行深拷贝 - 如果是
copy
,拷贝后的对象不可变 - 如果是
mutableCopy
,拷贝后的对象可变
区别:
- 浅拷贝:拷贝指针,不开辟内存地址
- 深拷贝:拷贝指针和内容,开辟内存地址(存放拷贝的内容)
使用:
修饰不可变对象(NSString
,NSArray
,NSDictionary
等)用copy
,修饰可变对象(NSMutableString
,NSMutableArray
,NSMutableDictionary
等)用strong
C、copy和strong的区别
// 第二种场景:用NSMutableString直接赋值
NSMutableString *originStr = [NSMutableString stringWithFormat:@"hello,originStr"];
self.strongStr = originStr;
self.copyyStr = originStr;
[originStr setString:@"hello,I changed"];
NSLog(@"originStr 对象地址: %p ,对象指针地址:%p ,对象的值:%@", originStr, &originStr, originStr);
NSLog(@"strongStr 对象地址: %p ,对象指针地址: %p ,对象的值:%@", _strongStr, &_strongStr, _strongStr);
NSLog(@"copyyStr 对象地址: %p ,对象指针地址:%p ,对象的值:%@", _copyyStr, &_copyyStr, _copyyStr);
2018-09-06 09:23:02.871307+0800 PropertyDemo[2707:246046] originStr 对象地址: 0x60000024f630 ,对象指针地址:0x7ffee00bca28 ,对象的值:hello,I changed
2018-09-06 09:23:02.871465+0800 PropertyDemo[2707:246046] strongStr 对象地址: 0x60000024f630 ,对象指针地址: 0x7fb9cf40ea90 ,对象的值:hello,I changed
2018-09-06 09:23:02.871570+0800 PropertyDemo[2707:246046] copyyStr 对象地址: 0x60000024fcc0 ,对象指针地址:0x7fb9cf40ea98 ,对象的值:hello,originStr
疑问:self.copyyStr值:hello,originStr 终于是我们想要的结果
_copyyStr = originStr;和self.copyyStr = originStr;有什么区别?
原因:
用@property来声明属性变量时,编译器会自动为我们生成一个以下划线加属性名命名的实例变量(@synthesize copyyStr = _copyyStr),并且生成其对应的getter、setter方法。
1.self.copyyStr = originStr赋值时,会调用coppyStr的setter方法
2._copyyStr = originStr 赋值时给_copyyStr实例变量直接赋值,并不会调用copyyStr的setter方法
而在setter方法中有一个非常关键的语句:
_copyyStr = [copyyStr copy];
结论:
使用self.copyyStr = originStr 赋值时,调用copyyStr的setter方法,setter方法对传入的copyyStr做了次深拷贝生成了一个新的对象赋值给_copyyStr,所以_copyyStr指向的地址和对象值都不再和originStr相同。
总结
由上面的例子可以得出:
1.当原字符串是NSString时,由于是不可变字符串,所以,不管使用strong还是copy修饰,都是指向原来的对象,copy操作只是做了一次浅拷贝。
2.当源字符串是NSMutableString时,strong只是将源字符串的引用计数加1,而copy则是对原字符串做了次深拷贝,从而生成了一个新的对象,并且copy的对象指向这个新对象。
所以,如果源字符串是NSMutableString的时候,使用strong只会增加引用计数。但是copy会执行一次深拷贝,会造成不必要的内存浪费。而如果原字符串是NSString时,strong和copy效果一样,就不会有这个问题。
但是,我们一般声明NSString时,也不希望它改变,所以一般情况下,建议使用copy,这样可以避免NSMutableString带来的错误。