經(jīng)常在論壇和群里看到有人問(wèn)拷貝相關(guān)的問(wèn)題,回答的總是五花八門、千奇百怪。如果你對(duì)幾種拷貝的概念還不是很清晰,這篇文章會(huì)有幫助。
什么是淺拷貝
在談?wù)撋羁截?、淺拷貝等概念之前,先要清楚什么叫拷貝。拷貝(copy)就是復(fù)制。當(dāng)我們已經(jīng)有一個(gè)對(duì)象例如:
NSString *str = @"abc";
那么我想有一個(gè)str2和str的值一樣該怎么做呢?最簡(jiǎn)單的辦法就是這樣:
NSString *str2 = str;
實(shí)際上,這就是淺拷貝,str和str2的內(nèi)存地址是一樣的。也就是說(shuō)兩個(gè)指針指向了同一塊內(nèi)存,因此實(shí)際上并沒(méi)有東西被復(fù)制出來(lái),就好比文件的快捷方式,無(wú)論一個(gè)文件有多少快捷方式,這個(gè)文件始終只有一個(gè)。那么如果我不想要快捷方式,就想要兩個(gè)文件呢?
NSString *str3 = [str copy];
理論上來(lái)說(shuō),這樣會(huì)劃分新的內(nèi)存地址,生成新的對(duì)象,但是實(shí)際打印會(huì)發(fā)現(xiàn)str和str3的地址是一樣的。這是因?yàn)镺C對(duì)NSString做了內(nèi)存管理的優(yōu)化,這種值相同的string會(huì)直接淺拷貝。這也說(shuō)明,正常情況下NSString是不需要深拷貝的。
什么是深拷貝
那么什么時(shí)候需要深拷貝呢?其實(shí)深拷貝在開發(fā)中經(jīng)常用到:
@property (nonatomic, copy) NSString *name;
類似這樣的屬性項(xiàng)目中肯定多的數(shù)不清(當(dāng)然如果你寫成@property (nonatomic, strong) NSString *name;是不對(duì)的,你的項(xiàng)目會(huì)有可能出現(xiàn)莫名其妙的bug)。見名知意,聲明為copy的屬性在被賦值的時(shí)候?qū)嶋H上是會(huì)執(zhí)行copy方法的,就像這樣:
- (void)setName:(NSString *)name{
_name = [name copy];
}
為什么要這么做呢?假如我們就將name聲明為strong。NSString有個(gè)子類NSMutableString,我們是可以將NSMutableString對(duì)象賦值給NSString的,像這樣:
NSMutableString *mutableName = [NSMutableString stringWithString:@"Mike"];
self.name = mutableName;
然而如果我們?cè)诤竺娴拇a中修改了mutableName的值,name的值也會(huì)隨之改變。這當(dāng)然是不合理的,NSString的值應(yīng)該是不變的。而copy的作用就是這個(gè)。通過(guò)copy方法,創(chuàng)建了一個(gè)新的值和mutableName相同的對(duì)象,所以mutableName的值改變并不會(huì)影響到name。
什么是可變拷貝mutableCopy
同樣見名知意,就是拷貝出一個(gè)可變的對(duì)象出來(lái)。例如:
NSMutableString *mutableStr = [@"abc" mutableCopy];
通過(guò)對(duì)NSString進(jìn)行mutableCopy而產(chǎn)生了一個(gè)NSMutableString。我見過(guò)一些人創(chuàng)建mutableString就是這樣寫的,但是從代碼規(guī)范和效率的角度講,這樣做是不推薦的。
copy的妙用
copy方法除了可以對(duì)對(duì)象進(jìn)行深拷貝以外還有個(gè)優(yōu)點(diǎn)就是,相比于重新創(chuàng)建一個(gè)對(duì)象,copy的效率更高。例如要?jiǎng)?chuàng)建一百個(gè)MyClass對(duì)象,實(shí)例化一個(gè)對(duì)象然后使用copy方法的效率要比實(shí)例化一百次高得多。