最近開發(fā)遇到的一個問題,就是copy和strong作為屬性的修飾詞的區(qū)別,看了好多文章,沒有幾篇能夠講的很明白的,所以自己就梳理了一編。
第一步:
定義個不可變的對象,分別用copy和strong來作為修飾詞
@property(nonatomic,strong) NSArray *strongArr;
@property (nonatomic,copy) NSArray *copyarr;
下面就來看看他們的區(qū)別
首先我們定義一個可變的對象,先來看賦值操作
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修飾的屬性這次內存地址發(fā)生了變化,是個新的內存地址,所以數組里面的參數沒有變化,為什么呢,后面講解。
再看看可變數組:
@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
)
和不可變的對象執(zhí)行結果是一樣的,都是在同一個內存地址,那么問題來了,我可以對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個數組只要有個一改變,都會發(fā)生改變,因為他們是在同一內存地址。
self.xxx=arr,打印結果和不可變的數組結果是一樣的,self.XXX也是從新生成了一個新的內存地址;
[self.copymutablearr addObject:@"這是copy修飾的可變數組添加的元素"];?
這時候對copy數組進行操作會崩潰掉,
問題來了為什么copy修飾的_xxx=arr就可以對_xxx進行操作,而self.xxx=arr對self.xxx進行操作就會崩潰呢;
看下面的數據


從類型上可以看出用copy修飾的,self.xxx=arr的時候可變數組變成了nssingleobjetarryi類型,他是說明只有一個元素,也不是可變數組的類型,如果沒有元素就是_NSArray0,而可變數組是_NSArrayM類型,無論有多少元素可變數組應該是_NSArayM標記;而且崩潰日志也提示沒有找到addObject:這個方法,說明copy修飾時用self.xxx進行被賦值的話就變成了不可變數組,前提是self.xxx才會有影響;
再來看兩張圖


當不可變數組被賦值的時候,self.xxx=arr,用strong和copy修飾時 類型是有區(qū)別的,而_xxx=arr,_xxx的類型是沒有區(qū)別的,原數組是什么類型被賦值的類型是源類型;
從上面四張圖可以得出結論;
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.語法會從新分配新的內存地址;
所以說平時開發(fā)過程中屬性修飾詞用copy的時候一定要注意self.語法會重新開辟新的線程,沒有strong修飾更加便捷,開內存就意味著消耗,慎用!