iOS中的深、淺、可變、不可變copy

這周由于公司招新人,面試官的一道關(guān)于copy和mutalbeCopy的問題引發(fā)了組員之間的激烈探討,這時有位號稱selfStrong的同學跑出了他的必殺技--葵花寶典,說關(guān)于深淺拷貝的問題,看這張表就行了:



看到這張表,臥槽,這不就是當時教我們的口訣嗎:“copy-指針拷貝-淺拷貝,mutableCopy-內(nèi)容拷貝-深拷貝”!,“只有不可變對象調(diào)用copy方法時是淺拷貝,其他情況都為深拷貝”。曾經(jīng)一段時間我確實也是靠是否mutable來區(qū)分深淺拷貝的,但經(jīng)過多次和毛毛可的探討和實際的測試,逐漸發(fā)現(xiàn)這種記憶方式的一些問題。

把拷貝方法稱為copy而非immutableCopy的原因在于,NSCopying不僅涉及給那些具有可變版本和不可變版本的類來使用,而且還要供其他一些類使用,而那些類沒有“可變”與“不可變”之分,所以說,把拷貝方法叫做immutableCopy不合適。 ----Effective OC 2.0

深拷貝/淺拷貝本來就是是兩組不同的概念,可變/不可變只決定對象的可變性,而拷貝這個概念本意就是產(chǎn)生一個對象的副本,至于是深拷貝還是淺拷貝,用毛毛可不知道從哪找的這句“deep copy copy everything”就能很好的判斷。因為OC中的copy(immutableCopy)、mutableCopy方法把可不可變和拷貝這兩種概念聯(lián)系在了一起,所以讓我們覺得是否可變和深淺拷貝兩者之間是一一對應的關(guān)系的,但其實想想swift或者別的語言我們肯定不會把var/let和copy/deepCopy聯(lián)系起來吧。

所以單純的說copy就是指針拷貝/淺拷貝或者mutableCopy就是內(nèi)容拷貝/深拷貝只能說在某些情況下是有這種一一對應的關(guān)系,但并不能作為一個放之四海而皆準的判斷規(guī)則,關(guān)于深淺拷貝的問題,我們應該按照不同的類型來區(qū)分。

容器類型

可以這樣總結(jié):

類型 操作 容器 內(nèi)容 操作返回容器的可變性 深淺拷貝
NS* copy 不可 /
NS* mutableCopy
NSMutable* copy 不可
NSMutable* mutableCopy
NS* initWithXX:copyItems: 不可
NSMutable* initWithXX:copyItems:

容器類默認的copy操作默認都是淺拷貝,默認都會生成一個新的容器(也就是開辟一塊新的內(nèi)存地址,至于NS類型返回就容器的問題下面會講到),要想實現(xiàn)容器類的深拷貝,蘋果對于NS及其子類容器類型都提供了一個initWithXX:copyItems:的init方法,給copyItems這個參數(shù)傳YES,該方法生成的新容器中的每個元素都相當于對舊容器中相對應的元素做了一次copy操作(前提是元素遵守了NSCopying協(xié)議),這樣新容器對象就是對舊容器對象的一份深拷貝。

或者利用歸檔和反歸檔技術(shù)來實現(xiàn)深拷貝:

//先將要拷貝的數(shù)組歸檔
NSMutableArray *dataArray = [NSMutableArray array];
NSdata *data = [NSKeyedArchiver archivedDataWithRootObject: dataArray];
//再將歸檔后的數(shù)據(jù)解檔賦值給新的數(shù)組
NSmutableArray *dataArray2 = [NSKeyedArchiver unarchiveOjjectWithData:data];

自定義對象類型:

1.首先遵守NSCopying\NSMutableCopying協(xié)議
2.重寫copyWithZone:/mutableCopyWithZone:方法并返回新對象

- (id)copyWithZone:(NSZone *)zone {
    ClassB *copyObject = [[[self class] allocWithZone:zone] init];
    copyObject.name = [self.name copy];
    return copyObject;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    ClassB *mutableCopyObject = [[[self class] allocWithZone:zone] init];
    copyObject.name = [self.name mutableCopy];
    return mutableCopyObject
}

王老師提到的關(guān)于自定義對象的mutableCopy的使用場景的問題,我想了想,如果一個Person有一個NSArray類型的arr屬性,他想產(chǎn)生一個能夠帶有mutableArr屬性的Person,那么就可以對這個Person對象進行mutableCopy操作,這樣copy出來的對象的屬性就都是mutable類型了,比這樣相當于對原來的對象進行一種“升級”,目前能想到的也只有這種場景了。

NSString類型

和葵花寶典中的一致:

類型 操作 內(nèi)存 內(nèi)容 可變性 深淺拷貝
NSSting copy 不可 /
NSSting mutableCopy
NSMutableString copy 不可
NSMutableString mutableCopy

按理說copy這一操作都應該開辟一塊新的內(nèi)存,至于為啥NSArray/NSString的copy返回的還是舊地址,我們推斷是蘋果做了優(yōu)化,因為對NSArray/NSString這些不可變類型copy后生成的新內(nèi)容和原來是完全一樣的,如果還去開辟一片新的內(nèi)存地址就造成了浪費,所以對于NS*類型的copy操作,本質(zhì)上和=的作用一直,就是個單純的賦值操作,指向原來的對象。

現(xiàn)階段對copy和mutableCopy的理解也就是這樣了,這樣分開理解感覺更容易理清楚copy/deepCopy和mutable/immutable之間的關(guān)系,有問題可以留言探討。

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

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

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