strong和copy的区别记录

316 阅读5分钟

作者君:经过浏览一些博客所得,方便自己浏览和积累。如有侵权,请联系我!!!

一、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.使用方式

点语法:

  1. 在等号左边即为set方法
  2. 在等号右边即为get方法

一般方法:

  1. 使用set方法:[A setName:@""];
  2. 使用get方法:[A name];

B、深拷贝和浅拷贝

  • 如果对象是不可变的,copy会进行浅拷贝,mutableCopy会进行深拷贝
  • 如果对象是可变的,那么无论是copy还是mutableCopy都会进行深拷贝
  • 如果是copy,拷贝后的对象不可变
  • 如果是mutableCopy,拷贝后的对象可变

区别:

  1. 浅拷贝:拷贝指针,不开辟内存地址
  2. 深拷贝:拷贝指针和内容,开辟内存地址(存放拷贝的内容)

使用:

修饰不可变对象(NSStringNSArrayNSDictionary等)用copy,修饰可变对象(NSMutableStringNSMutableArrayNSMutableDictionary等)用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带来的错误。

转载:www.jianshu.com/p/ac654c505…