當前位置:成語大全網 - 書法字典 - IOS深層拷貝和淺層拷貝

IOS深層拷貝和淺層拷貝

壹.概念和概述

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方法返回的對象是不可變的對象。

?千言萬語成就壹幅畫。