copy 與 mutablecopy

相信對(duì)于有一定iOS開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué)來(lái)說(shuō),對(duì)于copy關(guān)鍵字一定不陌生,從字義上來(lái)看,應(yīng)該就是復(fù)制一個(gè)對(duì)象,然后我們對(duì)于NSString類型的屬性,一般也用copy關(guān)鍵字。但是大家對(duì)于copy關(guān)鍵字真正有什么具體了解呢,什么時(shí)候用copy,什么時(shí)候用mutableCopy,區(qū)別又在哪里,對(duì)于內(nèi)存存儲(chǔ)上又有什么知識(shí)點(diǎn),我相信還有一部分同學(xué)一知半解。秉著鉆研探索的精神,我們來(lái)詳細(xì)的學(xué)習(xí)一下。

首先我們先說(shuō)兩個(gè)兩個(gè)概念:

淺復(fù)制:不拷貝對(duì)象本身,僅僅是拷貝指向?qū)ο蟮闹羔?br> 深復(fù)制:是直接拷貝整個(gè)對(duì)象內(nèi)存到另一塊內(nèi)存中

[圖片上傳失敗...(image-9e68bd-1524395644405)]

一般來(lái)說(shuō)像這種使用‘=’號(hào)賦值的對(duì)象,基本上都是淺復(fù)制

   UIView * view1 = [[UIView alloc]init];
   UIView * view2 = [[UIView alloc]init];
   view1 = view2;

[圖片上傳失敗...(image-769ab5-1524395644405)]

內(nèi)存地址一樣的,很簡(jiǎn)單,所以它也是我們說(shuō)的淺復(fù)制之一。

然后我們來(lái)來(lái)看copy這關(guān)鍵字;

copy的字面意思就是“復(fù)制”,它是產(chǎn)生一個(gè)副本的過(guò)程,再來(lái)看在iOS里,copy與mutableCopy都是NSObject里的方法,一個(gè)NSObject的對(duì)象要想使用這兩個(gè)函數(shù),那么類必須實(shí)現(xiàn)NSCopying協(xié)議或NSMutableCopying協(xié)議,并且是實(shí)現(xiàn)了一般來(lái)說(shuō)我們用的很多系統(tǒng)里的容器類已經(jīng)實(shí)現(xiàn)了這些方法。

[圖片上傳失敗...(image-20e23a-1524395644405)]

如果不遵守協(xié)議,直接使用[xxx copy],那么會(huì)直接導(dǎo)致程序崩潰,比如UIView這個(gè)類就不允許使用copy

'NSInvalidArgumentException', reason: '-[UIView copyWithZone:]: unrecognized selector sent to instance 0x7fd5605099f0'
*** First throw call stack:
some error....

然后我們?cè)賮?lái)看copy關(guān)鍵字的特點(diǎn):
修改源對(duì)象的屬性和行為,不會(huì)影響副本對(duì)象
修改副本對(duì)象的屬性和行為,不會(huì)影響源對(duì)象
一個(gè)對(duì)象可以通過(guò)copy和mutableCopy方法來(lái)創(chuàng)建一個(gè)副本對(duì)象
copy:創(chuàng)建的是不可變副本(NSString,NSArray,NSDictionary)
mutableCopy:創(chuàng)建的是可變副本(NSMutableString,NSMutableArray,NSMutableDictionary)

原則就是:修改新(舊)對(duì)象,不影響舊(新)對(duì)象!而且不一定產(chǎn)生新的對(duì)象?。▌澲攸c(diǎn))

看個(gè)例子:

   NSString * str = @"testStr";
   NSMutableString * mutableStr = [str mutableCopy];
   NSLog(@"%@,%p",str,str);
   NSLog(@"%@,%p",mutableStr,mutableStr);

打印

testStr,0x103b9f068
testStr,0x600000264d80

可以看到兩個(gè)對(duì)象的內(nèi)容完全一樣,但是地址空間變了,說(shuō)明開(kāi)辟了一塊新內(nèi)存供給副本,為什么這個(gè)會(huì)產(chǎn)生新的對(duì)象呢?
1.因?yàn)樵瓌t 修改新(舊)對(duì)象,不影響舊(新)對(duì)象,所以生成一個(gè)新的對(duì)象
2.因?yàn)橐郧暗膶?duì)象是個(gè)不可變對(duì)象,而通過(guò)mutableCopy拷貝出來(lái)的對(duì)象必須是一個(gè)可變的對(duì)象,所以必須生成一個(gè)新的對(duì)象

同理:

NSMutableString * mutableStr = [NSMutableString stringWithFormat:@"mutableStr"];
NSMutableString * str = [mutableStr mutableCopy];
[str appendString:@"123"];
NSLog(@"%@,%p",mutableStr,mutableStr);
NSLog(@"%@,%p",str,str);

打印

mutableStr,0x6080000778c0
mutableStr123,0x608000077bc0

文字內(nèi)容不同,對(duì)象地址不同,修改新(舊)對(duì)象,不影響舊(新)對(duì)象

相同的

  NSMutableString * mutableStr = [NSMutableString stringWithFormat:@"mutableStr"];
  NSString * str = [mutableStr copy];
  NSLog(@"%@,%p",mutableStr,mutableStr);
  NSLog(@"%@,%p",str,str);

打印

mutableStr,0x600000075900
mutableStr,0x600000035360

原理一樣,使用copy關(guān)鍵字,產(chǎn)生了一個(gè)新的不可變的對(duì)象

以上的例子我們可以發(fā)先,使用copy或者mutableCopy都有產(chǎn)生新對(duì)象,現(xiàn)在我們?cè)賮?lái)看一個(gè)例子

 NSString * str = @"str";
 NSString * copyStr = [str copy];
 NSLog(@"%@,%p",str,str);
 NSLog(@"%@,%p",copyStr,copyStr);

打印

str,0x10c65e068
str,0x10c65e068

這下我們發(fā)現(xiàn),兩個(gè)對(duì)象的內(nèi)存地址完全一樣,所以系統(tǒng)并沒(méi)有創(chuàng)建一個(gè)新對(duì)象,這是為什么呢?
當(dāng)我們對(duì)一個(gè)不可變對(duì)象(NSString類型)使用copy關(guān)鍵字的時(shí)候,系統(tǒng)是不會(huì)產(chǎn)生一個(gè)新對(duì)象,因?yàn)樵瓉?lái)的對(duì)象是不能修改的,拷貝出來(lái)的對(duì)象也是不能修改的,那么既然兩個(gè)都不可以修改,所以這兩個(gè)對(duì)象永遠(yuǎn)也不會(huì)影響到另一個(gè)對(duì)象(符合我們說(shuō)的“修改新(舊)對(duì)象,不影響舊(新)對(duì)象”原則),系統(tǒng)為了節(jié)省內(nèi)存,所以就不會(huì)產(chǎn)生一個(gè)新的對(duì)象了。

那么問(wèn)題來(lái)了, copy到底是深拷貝還是淺拷貝?
我相信有的同學(xué)認(rèn)為只要是使用copy關(guān)鍵字,那么肯定都是深拷貝,這樣是很不嚴(yán)謹(jǐn)?shù)?,就比如上個(gè)例子,雖然使用了copy,但是指針地址是一樣,那么它就應(yīng)該是淺拷貝。
所以是否是深淺拷貝,是否創(chuàng)建新的對(duì)象,是由程序運(yùn)行的環(huán)境所造成的,并不是一概而論。

對(duì)于NSArray,NSDictionary,道理也是相同的。

現(xiàn)在再讓我們看下copy的內(nèi)存管理:

淺拷貝不會(huì)生成新的對(duì)象,所以系統(tǒng)會(huì)對(duì)以前的對(duì)象進(jìn)行一次retain,深拷貝會(huì)產(chǎn)生新的對(duì)象,系統(tǒng)不會(huì)對(duì)以前的對(duì)象進(jìn)行retain。

接著我們來(lái)看下copy與Block的配合使用

首先我們還是回顧一個(gè)概念

block默認(rèn)存儲(chǔ)在棧中,棧中的Block訪問(wèn)到的外界對(duì)象,不會(huì)對(duì)應(yīng)進(jìn)行retain
block如果在堆中,在block中訪問(wèn)了外界的對(duì)象,會(huì)對(duì)外界的對(duì)象進(jìn)行一次retian

因?yàn)閎lock在什么時(shí)候執(zhí)行是不確定的,所以如果block里外部對(duì)象被提前釋放了,那么如果這時(shí)候block執(zhí)行了,造成野指針異常,程序crash。

所以對(duì)于Block來(lái)說(shuō),我們一般都用copy關(guān)鍵字修飾.

#import <Foundation/Foundation.h>

typedef void(^TestBlock)(NSString * str);

@interface Model : NSObject

@property (nonatomic,copy) TestBlock testblock;

@end

使用copy保存block,這樣可以保住block中,避免以后調(diào)用block的時(shí)候,外界的對(duì)象已經(jīng)釋放了

作者:司機(jī)王
鏈接:http://www.itdecent.cn/p/700f58eb0b86
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 相信對(duì)于有一定iOS開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué)來(lái)說(shuō),對(duì)于copy關(guān)鍵字一定不陌生,從字義上來(lái)看,應(yīng)該就是復(fù)制一個(gè)對(duì)象,然后我們...
    司機(jī)王閱讀 13,874評(píng)論 8 48
  • 淺拷貝與深拷貝 淺拷貝:指針拷貝,不產(chǎn)生新的對(duì)象,源對(duì)象的引用計(jì)數(shù)器+1 深拷貝:對(duì)象拷貝,會(huì)產(chǎn)生新的對(duì)象,源對(duì)象...
    SkyMing一C閱讀 889評(píng)論 0 6
  • 這場(chǎng)催心折骨的鬼雨,該是一滴濕漉漉的靈魂。 窗外,在喊誰(shuí)?
    HH黑框框閱讀 269評(píng)論 3 8
  • 2015冠軍單曲 1.Blank Space--Taylor Swift 2.Uptown Funk--Mak R...
    歐音美樂(lè)閱讀 305評(píng)論 0 1
  • 為期兩周的行動(dòng)課結(jié)束了,雖然只有第一次跟著直播聽(tīng)但是每一次都沒(méi)有落下,雖然報(bào)課程的時(shí)候糊里糊涂的,也不知道...
    Theresa文進(jìn)閱讀 289評(píng)論 0 0

友情鏈接更多精彩內(nèi)容