1,淺復制
?淺拷貝是內存地址的拷貝,因此目標對象指針和源對象指向同壹個內存空間。當內存被破壞後,指向這個內存的幾個指針需要重新定義才能使用,否則就會變成野指針。
?淺拷貝是將指針復制到原對象,使原對象的引用計數為+1,可以理解為創建壹個新的指向原對象的指針,而不是創建壹個全新的對象。
2.深層拷貝
?深度復制是指復制壹個對象的特定內容,內存地址是自己分配的。復制後,雖然兩個對象的值相同,但內存地址不同,兩個對象互不影響,互不幹擾。
深度副本是壹個新對象的副本,具有相同的值,但內存地址完全不同,創建後與原對象無關。
3.總結:
深層拷貝是內容拷貝,淺層拷貝是指針拷貝。本質區別在於:
妳想打開壹個新的內存地址嗎
會影響內存地址的引用計數嗎?
二、實例分析
?在iOS中,深度復制和淺層復制更復雜,涉及容器和非容器、可變和不可變對象的復制和可變復制。以下實例逐壹分析:
1,非集合對象的副本和可變副本
?1.1不可變對象NSString?
-(void)nomutablenstringtest
{
ns string * str 1 = @ " test 001 ";
NSMutableString * str 2 =[str 1 copy];
//copy返回不可變對象,str2不能修改,所以會崩潰。
//[str 2 appendString:@ " test "];
NSMutableString * str 3 =[str 1 mutable copy];
[str 3 appendString:@ " modify "];
NSLog(@"str1:%p - %@ \r\n ",str1,str 1);
NSLog(@"str2:%p - %@ \r\n ",str2,str 2);
NSLog(@"str3:%p - %@ \r\n ",str3,str 3);
}
?打印結果:
2017-07-2018:02:10.642 beck . Wang
解析:str1,str2地址與str3地址相同不同,NSString的副本是淺副本,副本返回的對象是不可變對象;MutableCopy是深層副本。
?1.2可變對象NSMutableString
- (void)可變字符串測試
{
NSMutableString * mstr 1 =[NSMutableString string withstring:@ " test 002 "];
NSMutableString * mstr 2 =[mstr 1 copy];
//copy返回不可變對象,mstr2不能修改,所以會崩潰。
//[str 2 appendString:@ " test "];
NSMutableString * mstr 3 =[mstr 1 mutable copy];
[mstr 3 appendString:@ " modify "];
NSLog(@"mstr1:%p - %@ \r\n ",mstr1,mstr 1);
NSLog(@"mstr2:%p - %@ \r\n ",mstr2,mstr 2);
NSLog(@"mstr3:%p - %@ \r\n ",mstr3,mstr 3);
}
打印結果:
2017-07-2018:14:35.789
分析:mstr1,mstr2,mstr3地址不同。NSMutableString對象copy和mutablecopy都是深度副本,copy返回的對象是不可變對象。
2.集合對象的復制和可變復制
2.1不可變對象NSArray
- (void)可變數組測試
{
NSArray * arry 1 =[[NSArray alloc]initWithObjects:@ " value 1 " ,@ " value 2 ",nil];
NSArray * arry 2 =[arry 1 copy];
NSArray * arry 3 =[arry 1 mutable copy];
NSLog(@"arry1:%p - %@ \r\n ",arry1,arry 1);
NSLog(@"arry2:%p - %@ \r\n ",arry2,arry 2);
NSLog(@"arry3:%p - %@ \r\n ",arry3,arry 3);
}
打印結果:
王[15438+0:0x 60800003 b480-(
值1,
價值2
)2017-2018:33:53.708 beck . Wang[1502:194476]arry 2:0x 60800003 b480-(
值1,
價值2
)2017-2018:33:53.708 beck . Wang[1502:194476]arry 3:0x 60800004 CD 20-(
值1,
價值2
)
分析:arry1,arry2地址相同,arr3地址不同,NSArray的副本是淺副本,copy返回的對象是不可變對象;MutableCopy是深層副本。
?2.2可變對象NSMutableArray
- (void) NSMutableArrayTest
{
NSMutableArray * marry 1 =[[NSMutableArray alloc]initWithObjects:@ " value 1 " ,@ " value 2 ",nil];
NSMutableArray * marry 2 =[marry 1 copy];
//copy返回壹個不可變的對象。marry2無法修改,所以會崩潰。
//[marry 2 add object:@ " value 3 "];
NSMutableArray * marry 3 =[marry 1 mutable copy];
NSLog(@"marry1:%p - %@ \r\n ",marry1,marry 1);
NSLog(@"marry2:%p - %@ \r\n ",marry2,marry 2);
NSLog(@"marry3:%p - %@ \r\n ",marry3,marry 3);
}
打印結果:
王[1577:204641:0x 600000048 d60-(
值1,
價值2
)2017-2018:55:43.244 beck . Wang
值1,
價值2
)2017-2018:55:43.244 beck . Wang[1577:204641]marry 3:0x 6000000494 B0-(
值1,
價值2
)
分析:marry1、marry2和marr3的地址不同。NSMutableArray對象copy和mutablecopy都是深度副本,copy返回的對象是不可變對象。
需要特別註意的是:對於集合類的可變對象,深度復制不是嚴格的深度復制,而只是單層深度復制,即存儲在內存中的值(即數組中的元素仍然是數組元素值的家鄉,沒有其他副本),稱為單層深度復制。
例如:
-(void)singlensmatablearraytest
{
NSMutableArray * marry 1 =[[NSMutableArray alloc]init];
NSMutableString * mstr 1 =[[NSMutableString alloc]init withstring:@ " value 1 "];
NSMutableString * mstr 2 =[[NSMutableString alloc]init withstring:@ " value 2 "];
[marry 1 add object:mstr 1];
[marry 1 add object:mstr 2];
NSMutableArray * marry 2 =[marry 1 copy];
NSMutableArray * marry 3 =[marry 1 mutable copy];
NSLog(@"marry1:%p - %@ \r\n ",marry1,marry 1);
NSLog(@"marry2:%p - %@ \r\n ",marry2,marry 2);
NSLog(@"marry3:%p - %@ \r\n ",marry3,marry 3);
NSLog(@ "數組元素地址:值1:% p-value2:% p \ r \ n ",marry 1 [0],marry 1[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marry2 [0],marry 2[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marry3 [0],marry 3[1]);
NSLog(@"\r\n -修改原始值後);
[mstr 1 append format:@ " AAA "];
NSLog(@"marry1:%p - %@ \r\n ",marry1,marry 1);
NSLog(@"marry2:%p - %@ \r\n ",marry2,marry 2);
NSLog(@"marry3:%p - %@ \r\n ",marry3,marry 3);
NSLog(@ "數組元素地址:值1:% p-value2:% p \ r \ n ",marry 1 [0],marry 1[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marry2 [0],marry 2[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marry3 [0],marry 3[1]);
}
打印結果:
王[1750:23017]marry 1:0x 608000004 ae00-(
值1,
價值2
)2017-2019:48:24.539 beck . Wang[1750:230132]marry 2:0x 6080000023 f00-(
值1,
價值2
2017-2019:48:24.539 beck . Wang[1750:230132]marry 3:0x 60800004 ABC 0-(
值1,
價值2
)2017-07-2019:48:24.540 beck . Wang[1750:230132]數組元素地址:value 1:0x 60800006 df 40-value 2:0x 60800006 CB 402017-07-2065438+
值1aaa,
價值2
王[1750:230132]marry 2:0x 6080000023 f00-(
值1aaa,
價值2
王[1750:230132]marry 3:0x 608000004 ABC 0-(
值1aaa,
價值2
)2017-07-2019:48:24.541 beck . Wang[1750:230132]數組元素地址:值1:0x 608000006 df 40-值2:0x 6080006 CB 402017-07-2064
分析:原始值修改前,marry1、marry2、marr3的地址都不壹樣。很明顯,copy和mutableCopy都是深度副本,但從原始值修改後的打印結果來看,這裏的深度副本只是單層深度副本:內存地址是新打開的,但數組中的值仍然指向原始數組,這樣marry2 marr3中的值就可以在原始值修改後進行修改。另外,從打印出來的數組元素地址可以明顯看出,marry1、marry和marr3的數組元素地址在修改前後完全相同,進壹步證明了這壹點。
?2.3思維拓展:收集對象的完整深層拷貝
對於2.2中提到的對象,深度拷貝只是單層深度拷貝。有什麽方法可以實現每壹層的深度復制?答案是肯定的。目前,我們可以這樣做:
?(1)歸檔解決方案
- (void) deplyFullCopy
{
NSMutableArray * marry 1 =[[NSMutableArray alloc]init];
NSMutableString * mstr 1 =[[NSMutableString alloc]init withstring:@ " value 1 "];
NSMutableString * mstr 2 =[[NSMutableString alloc]init withstring:@ " value 2 "];
[marry 1 add object:mstr 1];
[marry 1 add object:mstr 2];
ns data * data =[nskeydarchiver archivedDataWithRootObject:marry 1];
NSArray * marray 2 =[nskeydunarchiver unarchiveTopLevelObjectWithData:數據錯誤:nil];
NSLog(@"marry1:%p - %@ \r\n ",marry1,marry 1);
NSLog(@"marry2:%p - %@ \r\n ",marray2,marray 2);
NSLog(@ "數組元素地址:值1:% p-value2:% p \ r \ n ",marry 1 [0],marry 1[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marray2 [0],marray 2[1]);
}
?打印結果:
王[1833:242158]marry 1:0x 6000000048 a00-(
值1,
價值2
王[1833:242158]marry 2:0x 600000049780-(
值1,
價值2
)2017-07-2020:04:38.726 beck . Wang[1833:242158]數組元素地址:值1:0x 60000006300-值2:0x 6000000670002017-07-2020:04:38.726王。
解析:我們可以看到,打開新的內存地址時,數組元素的指針地址是不同的,實現了完整的深度復制。
(2)-(instance type)init with array:(NSArray & lt;ObjectType & gt*)數組copyItems:(BOOL)標誌;
- (void) deplyFullCopy2
{
NSMutableArray * marry 1 =[[NSMutableArray alloc]init];
NSMutableString * mstr 1 =[[NSMutableString alloc]init withstring:@ " value 1 "];
NSMutableString * mstr 2 =[[NSMutableString alloc]init withstring:@ " value 2 "];
[marry 1 add object:mstr 1];
[marry 1 add object:mstr 2];
NSArray * marray 2 =[[NSArray alloc]init with array:marry 1 copy items:YES];
NSLog(@"marry1:%p - %@ \r\n ",marry1,marry 1);
NSLog(@"marry2:%p - %@ \r\n ",marray2,marray 2);
NSLog(@ "數組元素地址:值1:% p-value2:% p \ r \ n ",marry 1 [0],marry 1[1]);
NSLog(@ "數組元素地址:value1:% p-value2:% p \ r \ n ",marray2 [0],marray 2[1]);
}
打印結果:
王[1868:2461000050320-(
值1,
價值2
)2017-07-2020:08:04.202 beck . Wang[1868:246161]marry 2:0x 6100002214c 0-(
值1,
價值2
)2017-07-2020:08:04.202 beck . Wang[1868:246161:0x 61000265600-value 2:0x 610002664002017
?分析:同上。
三。指導方針
?No1:可變對象的copy和mutableCopy方法都是深度副本(以區分完整的深度副本和單層的深度副本)。
?不可變對象的復制方法是淺層復制,可變復制方法是深層復制。
?copy方法返回的對象是不可變的對象。
?千言萬語成就壹幅畫。