iOS copy/strong作为修饰词对属性值的影响

最近开发遇到的一个问题,就是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修饰更加便捷,开内存就意味着消耗,慎用!

你可能感兴趣的:(iOS copy/strong作为修饰词对属性值的影响)