1.Copy 和 MutbaleCopy 介紹
2.淺拷貝和深拷貝
3.block為何使用copy挪钓?
4.使用copy的優(yōu)勢
5.總結(jié)
1. Copy和MutbaleCopy介紹
如果我們需要?jiǎng)?chuàng)建一個(gè)對象蒙具,使該對象與源對象的內(nèi)容一致,那么就可以使用到拷貝(copy或mutablecopy)诀姚,下面來看一段簡單的代碼:
NSString* string =@"egg";
[stringcopy];//拷貝出的內(nèi)容為egg的NSString類型字符串
[stringmutableCopy];//拷貝出的內(nèi)容為egg的NSMutableString類型字符串
NSArray* array =@[@"egg"];
[arraycopy];//拷貝出內(nèi)容與array相同的NSArray類型數(shù)組
[arraymutableCopy];//拷貝出內(nèi)容與array相同的NSMutableArray類型數(shù)組
NSDictionary* Goods =@{@"name":@"egg"};
[Goodscopy];//拷貝出內(nèi)容與Goods相同的NSDictionary類型字典
[GoodsmutableCopy];//拷貝出內(nèi)容與Goods相同的NSMutablDictionary類型字典
如注釋所述:
使用copy拷貝出來的對象類型總是不可變類型(例如:NSString,NSArray,NSDictionary等)假哎;
使用mutableCopy拷貝出來的對象類型總是可變類型(例如:NSMutableString,NSMutableArray,NSMutablDictionary等)芒帕;
2. 深拷貝和淺拷貝
網(wǎng)上有很多討論深拷貝淺拷貝的文章歉嗓,有些文章甚至說copy都是淺拷貝mutableCopy都是深拷貝,其實(shí)這種觀點(diǎn)并不絕對正確背蟆。
那何為淺拷貝何為深拷貝呢鉴分?
淺拷貝:拷貝出來的對象與源對象地址一致。簡單說就是如果修改了拷貝對象的值带膀,那么源對象也會(huì)隨之相應(yīng)改變志珍。
深拷貝:拷貝出來的對象與源對象地址不一致。簡單說就是無論如何修改拷貝對象都不會(huì)對源對象產(chǎn)生任何影響垛叨。
為什么說網(wǎng)上那些“copy都是淺拷貝mutableCopy都是深拷貝”的說法說法不準(zhǔn)確呢伦糯,這里就有一種情況不符合它的表述:
當(dāng)使用copy從一個(gè)可變的對象拷貝出來一個(gè)不可變的對象時(shí),這種情況就屬于深拷貝而不是淺拷貝嗽元!NSMutableDictionary* EggGoods = [NSMutableDictionarydictionaryWithObjectsAndKeys:@"name",@"redEgg",nil];NSDictionary* goods1 = [EggGoodscopy];//屬于深拷貝范疇
這里需要留意一下敛纲,其實(shí)深拷貝與淺拷貝也有相對之分。
對于NSString對象剂癌,淺拷貝和深拷貝沒有任何異議淤翔,但是對于容器類對象比如:NSArray,NSDcitionary佩谷,NSSet這些容器類對象旁壮,當(dāng)然淺拷貝依然是淺拷貝(指針拷貝),但是深拷貝就不同了,這里會(huì)有兩種情況谐檀,我們暫時(shí)可以把這種區(qū)別分為不完全深拷貝和完全深拷貝抡谐。
不完全深拷貝:只拷貝容器對象,對于容器內(nèi)部的對象只保存一份引用(拷貝了一個(gè)外殼兒)桐猬;
完全深拷貝:連同容器內(nèi)部的對象完全拷貝一份出來麦撵;
這種區(qū)分可以參照下圖:
修改copyarr1不會(huì)影響到arr1,但如果通過copyarr1修改數(shù)組內(nèi)的obj,對應(yīng)的源arr1內(nèi)的obj也會(huì)隨之改變课幕。
無論是修改copyarr2厦坛,還是通過copyarr2修改數(shù)組內(nèi)部的obj五垮,對源arr2都沒有任何影響乍惊。
通常默認(rèn)狀態(tài)下深拷貝指的是不完全深拷貝,如果想實(shí)現(xiàn)完全深拷貝放仗,需要自己重寫copyWithZone:方法润绎。給一段筆者調(diào)試的代碼看下吧:
// Egg
- (id)copyWithZone:(NSZone*)zone {
Egg* egg = [[EggallocWithZone:zone]init];
egg.name=self.name;
egg.weight=self.weight;
returnegg;
}
//完全深拷貝測試code
Egg* egg1 = [[Eggalloc]init];
Egg* egg2 = [[Eggalloc]init];
NSArray* arr1 =@[egg1,egg2];
NSArray* copyarr1 = [arr1copy];
NSLog(@"------->源數(shù)據(jù):%@/n拷貝數(shù)據(jù):%@",arr1,copyarr1);
這樣就簡單實(shí)現(xiàn)了完全深拷貝。(蘋果官方文檔說copy方法內(nèi)部默認(rèn)會(huì)調(diào)用copyWithZone:方法,但是NSArray執(zhí)行copy時(shí)并沒有調(diào)用它莉撇,按照官方文檔可能是OC已經(jīng)棄用了zone概念呢蛤,當(dāng)然可以利用分類重寫copy方法來解決)。
3. 很多時(shí)候使用block會(huì)用copy來修飾棍郎,為什么呢其障?
block通常會(huì)作為對象被使用,所以block理論上是可以retain或release的涂佃,特殊之處在于創(chuàng)建block的時(shí)候它的內(nèi)存是默認(rèn)分配在棧上而不是堆上励翼,這就決定了block的作用域僅限于當(dāng)前上下文,在該作用域之外的地方調(diào)用這個(gè)block辜荠,程序就會(huì)carsh汽抚。
之所以使用copy來修飾block,是因?yàn)閏opy將block從內(nèi)存棧區(qū)移到了堆區(qū),這樣就可以在block定義域之外有調(diào)用需求的地方來安全的調(diào)用它伯病。其實(shí)ARC環(huán)境下使用copy與strong都一樣造烁,因?yàn)閎lock的retain就是用copy來實(shí)現(xiàn)的,習(xí)慣用copy的程序員可能像筆者一樣是一路從MRC走來的午笛。
4. 使用copy的優(yōu)勢
相對于直接使用賦值語句惭蟋,使用copy來處理數(shù)據(jù)有時(shí)候可以避免與OC的多態(tài)性產(chǎn)生沖突,帶來不必要的維護(hù)成本開銷药磺。
看一段代碼:
打印信息
-------> Arr:(
"redegg!",
"blueegg!"
) , array:(
"redegg!",
"blueegg!"
)
這里明明看到可變數(shù)組添加對象是在賦值語句之后敞葛,但從打印看到,后添加的對象還會(huì)影響到不可變數(shù)組呢与涡?原因就是OC支持多態(tài)惹谐,表面上Arr是NSArray類型,其實(shí)骨子里是NSMutableArray對象驼卖。這種問題在排查調(diào)試的時(shí)候去分析就比較困難了氨肌。
那使用copy再來看下
打印信息
-------> Arr:(
"redegg!"
) , array:(
"redegg!",
"blueegg!"
)
這里使用copy可以保證無論賦值的是可變還是不可變數(shù)組,NSArray都不會(huì)再變酌畜。這也是為什么大多數(shù)時(shí)候NSString,NSArray,NSDictionary屬性用copy而不用strong修飾的原因怎囚。
總結(jié):網(wǎng)上也有很多寫的很好的關(guān)于copy和mutableCopy用法的總結(jié),筆者這里就不在贅述了,至于開發(fā)過程中遇到這方面的問題桥胞,只要細(xì)心一些恳守,按照用法規(guī)則多調(diào)試,都能夠解決贩虾。所提之處如有錯(cuò)誤催烘,歡迎大家指正。