iOS 你不一定了解的深淺拷貝

一、深淺拷貝

1、 什么是深拷貝?

深拷貝是對內(nèi)容的拷貝,復(fù)制內(nèi)容,同時有新的指針指向該內(nèi)存區(qū)域;

2、什么是淺拷貝?

淺拷貝只做指針復(fù)制,兩個指針指向同一處內(nèi)存空間;

3、對于拷貝,詳細(xì)來說有四方面內(nèi)容:

1、不可變對象的拷貝操作:immutableObjc -> copy
2、不可變對象的可變拷貝操作:immutableObjc -> mutableCopy
3、可變對象的拷貝操作:mutableObjc -> copy
4、可變對象的可變拷貝操作:mutableObjc -> mutableCopy

二、非集合對象的深淺拷貝(NSString、NSNumber...)

1、不可變對象的 copy 和 mutableCopy

NSString *string = @"string";
NSString *copyString = [string copy]; // 沒有產(chǎn)生新對象
NSMutableString *mutCopyString = [string mutableCopy]; // 產(chǎn)生新對象
    
NSLog(@"\n string = %p\n copyString = %p\n mutCopyString = %p", string, copyString, mutCopyString);

打印結(jié)果:

不可變對象的 copy 和 mutablecopy

結(jié)論:對不可變對象 copy 是淺拷貝,mutablecopy 是深拷貝;

2、可變對象的 copy 和 mutableCopy

NSMutableString *string = [NSMutableString stringWithString:@"mutString"];

NSString *copyString = [string copy]; // 產(chǎn)生新對象
NSMutableString *mutCopyString = [string mutableCopy];  // 產(chǎn)生新對象

NSLog(@"\n string = %p\n copyString = %p\n mutCopyString = %p", string, copyString, mutCopyString);

打印結(jié)果:

可變對象的 copy 和 mutablecopy

結(jié)論:對可變對象 copy 和 mutablecopy 都是深拷貝;

3、非集合對象的深淺拷貝:

  • immutableObjc -> copy 淺拷貝
  • immutableObjc -> mutableCopy 深拷貝
  • mutableObjc -> copy 深拷貝
  • mutableObjc -> mutableCopy 深拷貝

三、集合對象的深淺拷貝(NSArray、NSSet、NSDictionary)

1、集合的淺復(fù)制 (shallow copy)

集合的淺復(fù)制有非常多種方法。當(dāng)你進(jìn)行淺復(fù)制時,會向原始的集合發(fā)送retain消息,引用計數(shù)加1,同時指針被拷貝到新的集合。
現(xiàn)在讓我們看一些淺復(fù)制的例子:

NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSSet *shallowCopySet = [NSSet mutableCopyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];
2、集合的深復(fù)制 (deep copy)

方式一:用 initWithArray:copyItems: 將第二個參數(shù)設(shè)置為YES

NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];

如果使用這種方法深復(fù)制,集合里的每個對象都會收到 copyWithZone: 消息。如果集合里的對象遵循 NSCopying 協(xié)議,那么對象就會被深復(fù)制到新的集合。如果對象沒有遵循 NSCopying 協(xié)議,而嘗試用這種方法進(jìn)行深復(fù)制,會在運(yùn)行時出錯。copyWithZone: 這種拷貝方式只能夠提供一層內(nèi)存拷貝(one-level-deep copy),而非真正的深復(fù)制。

方式二:將集合進(jìn)行歸檔(archive),然后解檔(unarchive)

NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
3、集合的單層深復(fù)制 (one-level-deep copy)

什么是單層深復(fù)制呢?如果在多層數(shù)組中,對第一層進(jìn)行內(nèi)容拷貝,其它層進(jìn)行指針拷貝,這種情況,即為單層深復(fù)制。蘋果的官方文檔
蘋果認(rèn)為這種復(fù)制不是真正的深復(fù)制,而是將其稱為單層深復(fù)制(one-level-deep copy)。因此,有人對淺復(fù)制、單層深復(fù)制、深復(fù)制做了概念區(qū)分。

  • 淺復(fù)制(shallow copy):在淺復(fù)制操作時,對于被復(fù)制對象的每一層都是指針復(fù)制。
  • 單層深復(fù)制(one-level-deep copy):在深復(fù)制操作時,對于被復(fù)制對象,至少有一層是深復(fù)制。
  • 完全復(fù)制(real-deep copy):在完全復(fù)制操作時,對于被復(fù)制對象的每一層都是對象復(fù)制。

1、不可變對象的 copy 和 mutableCopy

 NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
 NSArray *copyArray = [array copy];
 NSMutableArray *mutCopyArray = [array mutableCopy];

 NSLog(@"\narray - %p\ncopy - %p\nmutCopy - %p", array, copyArray, mutCopyArray);

打印結(jié)果:

集合 immutable 對象的拷貝

結(jié)論:

  • 查看內(nèi)容,可以看到 copyArray 和 array 的地址是一樣的,而 mutCopyArray 和 array 的地址是不同的。說明 copy 操作進(jìn)行了指針拷貝,mutableCopy 進(jìn)行了內(nèi)容拷貝。
  • 需要強(qiáng)調(diào)的是:此處的內(nèi)容拷貝,僅僅是拷貝 array 這個對象,array 集合內(nèi)部的元素仍然是指針拷貝。這和上面的非集合 immutable 對象的拷貝還是挺相似的,

2、可變對象的 copy 和 mutableCopy

NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
NSArray *copyArray = [array copy];
NSMutableArray *mutCopyArray = [array mutableCopy];
    
NSLog(@"\narray - %p\ncopy - %p\nmutCopy - %p", array, copyArray, mutCopyArray);

查看結(jié)果:

集合 mutable 對象的拷貝

結(jié)論:

  • 根據(jù)打印結(jié)果可以看到 copyArray、mutCopyArray 和array 的內(nèi)存地址都不一樣,說明 copyArray、 mutCopyArray 都對 array 進(jìn)行了內(nèi)容拷貝。
  • 在集合類對象中,對 immutable 對象進(jìn)行 copy,是指針復(fù)制,mutableCopy 是內(nèi)容復(fù)制;對 mutable 對象進(jìn)行 copy 和 mutableCopy 都是內(nèi)容復(fù)制。但是:集合對象的內(nèi)容復(fù)制僅限于對象本身,對象元素仍然是指針復(fù)制。
4、集合對象的深淺拷貝
  • [immutableObject copy] // 淺復(fù)制
  • [immutableObject mutableCopy] //單層深復(fù)制
  • [mutableObject copy] //單層深復(fù)制
  • [mutableObject mutableCopy] //單層深復(fù)制

四、自定義對象

需要遵守<NSCopying>協(xié)議,并實(shí)現(xiàn)協(xié)議方法

CHIPerson *person = [[CHIPerson alloc] init];
CHIPerson *copyPerson = [person copy];
    
NSLog(@"\n person = %p\n copyPerson = %p\n", person, copyPerson);
- (id)copyWithZone:(NSZone *)zone
{
    CHIPerson *person = [[self class] allocWithZone:zone];
    return person;
}

打印結(jié)果:

自定義對象的拷貝操作

結(jié)論:自定義對象的拷貝操作是深拷貝

本文參考鏈接:

集合深淺拷貝以及經(jīng)常遇到的坑
iOS 集合的深復(fù)制與淺復(fù)制

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

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

  • 1、對象拷貝有兩種方式:淺復(fù)制和深復(fù)制。顧名思義,淺復(fù)制,并不拷貝對象本身,僅僅是拷貝指向?qū)ο蟮闹羔槪簧顝?fù)制是直接...
    滴答大閱讀 865評論 0 2
  • 本文為轉(zhuǎn)載: 作者:zyydeveloper 鏈接:http://www.itdecent.cn/p/5f776a...
    Buddha_like閱讀 1,021評論 0 2
  • 前言 不敢說覆蓋OC中所有copy的知識點(diǎn),但最起碼是目前最全的最新的一篇關(guān)于 copy的技術(shù)文檔了。后續(xù)發(fā)現(xiàn)有新...
    zyydeveloper閱讀 3,717評論 4 35
  • 轉(zhuǎn)載一、概念與總結(jié) 1、淺拷貝 淺拷貝就是對內(nèi)存地址的復(fù)制,讓目標(biāo)對象指針和源對象指向同一片內(nèi)存空間,當(dāng)內(nèi)存銷毀的...
    ilmari閱讀 406評論 0 2
  • 夜深了 看著周圍的一切都是那么的煩躁 是我錯了 還是你太…… 生氣 郁悶
    追夢的女孩2016閱讀 189評論 0 0

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