最近开发遇到的一个问题,就是copy和strong作为属性的修饰词的区别,看了好多文章,没有几篇能够讲的很明白的,所以自己就梳理了一编。
第一步:
定义个不可变的对象,分别用copy和strong来作为修饰词
@property(nonatomic,strong) NSArray *strongArr;
@property (nonatomic,copy) NSArray *copyarr;
下面就来看看他们的区别
首先我们定义一个可变的对象,先来看赋值操作
NSMutableArray *arr = [NSMutableArray new];
[arr addObject:@1];
_strongArr = arr;
_copyarr = arr;
[arr addObject:@2];
打印结果:
arr内存地址及指针指向:0x600002ebf030,0x7ffee4472158,
_strongArr:内存地址及指针指向:0x600002ebf030,0x7fcad6405080,
_copyarr:内存地址及指针指向:0x600002ebf030,0x7fcad6405088,
从内存地址来看无论是copy还是strong修饰的对象同属同一内存地址,所以对arr的值进行修改他们都会改变即使是把arr赋给不可变的对象后;因为指针不同但是指向的内存地址都是一样的;
再来想一个问题如果把_strongArr和_copyarr换成self.xxx的形式结果还是一样吗?
self.strongArr= arr; self.copyarr= arr; [arr addObject:@2];
打印结果:
arr内存地址及指针指向:0x6000022526a0,0x7ffee006b158,
arr数组里面的元素( 1, 2)
self.strongArr:内存地址及指针指向:0x6000022526a0,0x7f85a5f053d0,
strongArr数组里面的元素( 1, 2)
self.copyarr:内存地址及指针指向:0x600002e2bb00,0x7f85a5f053d8,
copyarr数组里面的元素( 1)
可以看到从打印出来的数据可以看到对self.strongArr和 self.copyarr赋值后 ,再对原始数组arr进行操作后,copy修饰的属性这次内存地址发生了变化,是个新的内存地址,所以数组里面的参数没有变化,为什么呢,后面讲解。
再看看可变数组:
@property(nonatomic,strong) NSMutableArray *strongMutableArr;
@property (nonatomic,copy) NSMutableArray *copymutablearr;
再看看copy和strong修饰的可变对象赋值操作
_strongMutableArr= arr;
_copymutablearr = arr;
[arr addObject:@2];
打印结果:
arr内存地址及指针指向:0x600001d84a50,0x7ffee8116158,
arr数组里面的元素(
1,
2
)
strongMutableArr:内存地址及指针指向:0x600001d84a50,0x7fd81bd03ac0,_
strongMutableArr数组里面的元素(
1,
2
)
_copymutablearr:内存地址及指针指向:0x600001d84a50,0x7fd81bd03ac8,
copymutablearr数组里面的元素(
1,
2
)
和不可变的对象执行结果是一样的,都是在同一个内存地址,那么问题来了,我可以对copymutablearr这个数组进行操作吗?
来试一下:
[_copymutablearr addObject:@"这是copy修饰的可变数组添加的元素"];
打印结果:
arr数组里面的元素(
1,
2,
"\U8fd9\U662fcopy\U4fee\U9970\U7684\U53ef\U53d8\U6570\U7ec4\U6dfb\U52a0\U7684\U5143\U7d20"
)
strongMutableArr数组里面的元素(
1,
2,
"\U8fd9\U662fcopy\U4fee\U9970\U7684\U53ef\U53d8\U6570\U7ec4\U6dfb\U52a0\U7684\U5143\U7d20"
)
copymutablearr数组里面的元素(
1,
2,
"\U8fd9\U662fcopy\U4fee\U9970\U7684\U53ef\U53d8\U6570\U7ec4\U6dfb\U52a0\U7684\U5143\U7d20"
)
可见这3个数组只要有个一改变,都会发生改变,因为他们是在同一内存地址。
self.xxx=arr,打印结果和不可变的数组结果是一样的,self.XXX也是从新生成了一个新的内存地址;
[self.copymutablearr addObject:@"这是copy修饰的可变数组添加的元素"];
这时候对copy数组进行操作会崩溃掉,
问题来了为什么copy修饰的_xxx=arr就可以对_xxx进行操作,而self.xxx=arr对self.xxx进行操作就会崩溃呢;
看下面的数据
self.xxx=arr _xxx=arr从类型上可以看出用copy修饰的,self.xxx=arr的时候可变数组变成了nssingleobjetarryi类型,他是说明只有一个元素,也不是可变数组的类型,如果没有元素就是_NSArray0,而可变数组是_NSArrayM类型,无论有多少元素可变数组应该是_NSArayM标记;而且崩溃日志也提示没有找到addObject:这个方法,说明copy修饰时用self.xxx进行被赋值的话就变成了不可变数组,前提是self.xxx才会有影响;
再来看两张图
self.xxx= arr(可变数组) _xxx=arr(可变数组)当不可变数组被赋值的时候,self.xxx=arr,用strong和copy修饰时 类型是有区别的,而_xxx=arr,_xxx的类型是没有区别的,原数组是什么类型被赋值的类型是源类型;
从上面四张图可以得出结论;
strong修饰的无论是可变的还是不可变的对象,无论是self.xxx还是_xxx,被赋值的对象类型都指向了赋值的对象类型arr,也就是说他们都是在同一内存地址下面,有一个动的其它的也会动;
copy修饰时_xxx无论是可变的还是不可变的,效果和strong修饰的是一样的,都是在同一个内存地址,唯一不一样的就是使用self.xxx时,会开辟新的内存地址;
注:copy修饰时,_xxx=arr时是可以对_xxx进行操作的,但是self.xxx=arr就不能对self.xxx进行操作了,应为self.xxx变成了不可变的了;
为什么self.xxx用copy修饰进行赋值操作的时候会开辟一个新的内存地址呢?
因为self.xxx进行赋值操作的话会走setter方法,而用copy修饰setter方法里面会进行一次深copy 操作,所以self.语法会从新分配新的内存地址;
所以说平时开发过程中属性修饰词用copy的时候一定要注意self.语法会重新开辟新的线程,没有strong修饰更加便捷,开内存就意味着消耗,慎用!
网友评论