iOS開發(fā)-對象拷貝

NSObject類提供了兩個用于拷貝的方法:- (id)copy 和- (id)mutableCopy,這兩個方法都可以復(fù)制已有對象的副本。由于oc中幾乎所有的類都繼承自根類NSObject,所以類中都有copy和mutableCopy兩個方法,那么是否就意味著擁有這兩個方法的對象可以直接調(diào)用這兩個方法進行拷貝了呢?

我們先定義一個AMPerson類繼承自NSObject 進行測試,代碼如下:

AMPerson *p1 = [[AMPerson alloc] init];

AMPerson *p2 = [p1 copy];

運行程序,發(fā)生崩潰,并輸出以下錯誤信息:

-[AMPerson copyWithZone:]: unrecognized selector sent to instance 0x7bf5e880? 意思是:AMPerson類中找不到copyWithZone:方法。

把copy方法換成mutableCopy,AMPerson *p2 = [p1 mutableCopy],運行之后,依然發(fā)生崩潰,提示信息如下:

-[AMPerson mutableCopyWithZone:]: unrecognized selector sent to instance 0x7a2415f0 意思是:AMPerson類中找不到mutableCopyWithZone:方法。

由以上錯誤可知:拷貝操作表面是調(diào)用copy和mutableCopy方法,其實底層是調(diào)用對象自身的copyWithZone和mutableCopyWithZone方法來完成實際的復(fù)制工作。copy返回實際上就是copyWithZone:方法的返回值;mutableCopy與mutableCopyWithZone:方法也是同樣的道理。

由該例就引出了下面的討論內(nèi)容了。就是對象具體要滿足什么條件,才可以被復(fù)制。


分為兩大類來討論:首先,自定義對象的復(fù)制。

要想自定義對象可以復(fù)制,那么該類就必須

一,遵守NSCopying 或 NSMutableCopying協(xié)議。

二,實現(xiàn)協(xié)議中copyWithZone或者mutableCopyWithZone方法。

所以讓我們的AMPerson類能夠復(fù)制自身,我們需要讓AMPerson實現(xiàn)NSCopying協(xié)議;然后實現(xiàn)copyWithZone:方法。

@interface AMPerson : NSObject ? <NSCopying>

@property (copy,nonatomic)NSString *name;

@end

@implementation AMPerson

- (id)copyWithZone:(NSZone *)zone {

?AMPerson *p = [[[self class] allocWithZone:zone] init];

p.name = [self.name copy];

?return p;

}

@end

然后再運行這兩句代碼

AMPerson *p1 = [[AMPerson alloc] init];

AMPerson *p2 = [p1 copy];

NSLog(@"p1 = %p,p2 = %p",p1,p2);

打印結(jié)果為:p1 = 0x7969cc40,p2 = 0x7969c6e0

結(jié)果表明:p1和p2是兩個地址不同的不同對象,復(fù)制操作成功。


其次,再來討論系統(tǒng)的對象的復(fù)制

copy方法用于復(fù)制對象的副本。通常來說,copy方法總是返回對象的不可修改的副本,即使對象本身是可修改的。例如,NSMutableString調(diào)用copy方法,將會返回不可修改的字符串對象。

mutableCopy方法用于復(fù)制對象的可變副本。通常來說,mutableCopy方法總是返回對象可修改的副本,即使被復(fù)制的對象本身是不可修改的。例如,程序調(diào)用NSString的mutableCopy方法,將會返回一個NSMutableString對象

下圖詳細列出了NSString、NSMutableString、NSArray、NSMutableArray、NSDictionary、NSMutableDictionary等分別調(diào)用copy與mutableCopy方法后的結(jié)果。

系統(tǒng)對象復(fù)制

深復(fù)制與淺復(fù)制

對象拷貝有兩種方式:淺拷貝和深拷貝。淺拷貝,并不拷貝對象本身,僅僅是拷貝指向?qū)ο蟮闹羔?;深拷貝是直接拷貝整個對象內(nèi)容到另一塊內(nèi)存中。再簡單些說:淺拷貝就是指針拷貝,深拷貝就是內(nèi)容拷貝。

接著,我們來討論一下多層數(shù)組的復(fù)制。

如果在多層數(shù)組中,對第一層進行內(nèi)容拷貝,其它層進行指針拷貝,這種情況是屬于深復(fù)制,還是淺復(fù)制?

如下所示

AMPerson *p1 = [[AMPerson alloc] init];

AMPerson *p2 = [[AMPerson alloc] init];

AMPerson *p3 = [[AMPerson alloc] init];

NSArray *p = @[p1,p2,p3];//數(shù)組

NSArray *pCopy = [p mutableCopy];//復(fù)制

NSLog(@"p = %p,pCopy = %p",p,pCopy); //打印結(jié)果: p = 0x7c268090,pCopy = 0x7c26af20

NSLog(@"p = %p,pCopy = %p",p[0],pCopy[0]); //打印結(jié)果:p = 0x7c26a6e0,pCopy = 0x7c26a6e0

打印結(jié)果表明:數(shù)組復(fù)制只是單單對于數(shù)組對象本身而言是深復(fù)制,而數(shù)組的成員對象默認仍然是淺拷貝的。我們稱之為單層深復(fù)制。

那么要想實現(xiàn)完全深復(fù)制該怎么辦呢? 尤其是當(dāng)該對象包含大量的指針類型的實例變量時,如果某些實例變量里再次包含指針類型的實例變量,那么實現(xiàn)完全深復(fù)制會更加復(fù)雜。上面的深復(fù)制就是因為集合對象中可能會包含指針類型的實例變量,從而導(dǎo)致深復(fù)制不完全。

把上面的復(fù)制代碼NSArray *pCopy = [p mutableCopy]換成NSArray *pCopy = [[NSMutableArray alloc] initWithArray:p copyItems:YES]即可。

AMPerson *p1 = [[AMPerson alloc] init];

AMPerson *p2 = [[AMPerson alloc] init];

AMPerson *p3 = [[AMPerson alloc] init];

NSArray *p = @[p1,p2,p3];

NSArray *pCopy = [[NSMutableArray alloc] initWithArray:p copyItems:YES];//復(fù)制

NSLog(@"p = %p,pCopy = %p",p,pCopy);//打印結(jié)果:p = 0x7a93af60,pCopy = 0x7a939680

NSLog(@"p = %p,pCopy = %p",p[0],pCopy[0]);//打印結(jié)果:p = 0x7a93c2e0,pCopy = 0x7a93c990

結(jié)果表明這次的復(fù)制是 完全深復(fù)制。不僅僅復(fù)制了第一層的數(shù)組對象,也復(fù)制了數(shù)組內(nèi)部的指針類型的實例變量。當(dāng)然內(nèi)部的實例變量要遵守NSCoping協(xié)議。

總結(jié)

對于對象的深復(fù)制的概念沒有必要那么糾結(jié),只要我們理解了復(fù)制的本質(zhì),并且運用到我們的業(yè)務(wù)場景,選擇我們想要的復(fù)制方式就可以。最主要的還是理解本質(zhì)并且學(xué)會使用。

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

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

  • 本文為轉(zhuǎn)載: 作者:zyydeveloper 鏈接:http://www.itdecent.cn/p/5f776a...
    Buddha_like閱讀 1,012評論 0 2
  • 1、對象拷貝有兩種方式:淺復(fù)制和深復(fù)制。顧名思義,淺復(fù)制,并不拷貝對象本身,僅僅是拷貝指向?qū)ο蟮闹羔?;深?fù)制是直接...
    滴答大閱讀 846評論 0 2
  • 為什么很多內(nèi)置類如UITableView的delegate屬性都是assign而不是retain? 所有的引用計數(shù)...
    煙雨平生花飛舞閱讀 1,278評論 0 3
  • 早晨醒來,難得地有一種清凈自在的感覺。 我猶豫了一下,沒有向往常一樣第一時間打開手機看推送,隱隱地覺得只要一打開,...
    Tina_Sun閱讀 400評論 0 7
  • 美好的生活 有人向往別墅豪車,有人向往海浪沙灘,有人向往都市繁華。我腦海中總是向往這樣的生活:青山綠水旁,三間平房...
    荷蓉閱讀 703評論 8 10

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