深 復 制:在複製操作時,對於被複制的對象至少有一層複製是對象複製。
完全複製:在複製操作時,對於被複制的對象的每一層複製都是對象複製。
注:1、在複製操作時,對於對象有n層是對象複製,我們可稱作n級深複製,此處n應大於等於1。
2、對於完全複製如何實現(目前通用的辦法是:迭代法和歸檔),這裏後續是否添加視情況而定,
暫時不做講解。
3、指針複製俗稱指針拷貝,對象複製也俗稱內容拷貝。
4、一般來講,
淺層複製:複製引用對象的指針。
深層複製:複製引用對象內容。
retain:始終是淺複製。引用計數每次加一。返回對象是否可變與被複制的對象保持一致。
copy:對於可變對象爲深複製,引用計數不改變;對於不可變對象是淺複製,
引用計數每次加一。始終返回一個不可變對象。
mutableCopy:始終是深複製,引用計數不改變。始終返回一個可變對象。
不可變對象:值發生改變,其內存首地址隨之改變。
可變對象:無論值是否改變,其內存首地址都不隨之改變。
引用計數:爲了讓使用者清楚的知道,該對象有多少個擁有者(即有多少個指針指向同一內存地址)。
最近有一個好朋友問我,什麼時候用到深淺複製呢?那麼我就把我所總結的一些分享給大家,希望能幫助你們更好的理解深淺複製喔!
那麼先讓我們來看一看下邊數組類型的轉換
1、不可變對象→可變對象的轉換:
NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
NSMutableArray *str2=[array1 mutableCopy];
2、可變對象→不可變對象的轉換:
NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];
NSArray *array1=[ array2 Copy];
3、可變對象→可變對象的轉換(不同指針變量指向不同的內存地址):
NSMutableArray *array1= [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
NSMutableArray *str2=[array1 mutableCopy];
通過上邊的兩個例子,我們可輕鬆的將一個對象在可變和不可變之間轉換,並且這裏不用考慮內存使用原則(即引用計數的問題)。沒錯,這就是深拷貝的魅力了。
4、同類型對象之間的導向保持(不同指針變量指向同一塊內存地址):
a、
NSMutableString *str1=[NSMutableString stringWithString:@"two day"];
NSMutableString *str2=[str1 retain];
[str1 release];
b、
NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
NSArray *str2=[array1 Copy];
[array1 release];
通俗的講,就是甲在執行交通導航任務,但接到上級新的命令要執行新的任務,那麼在甲執行新任務之前,需要有人替代甲繼續執行交通導航任務。這時候就要用到淺拷貝了。
則簡化爲:
問:什麼時候用到深淺拷貝?
答:深拷貝是在要將一個對象從可變(不可變)轉爲不可變(可變)或者將一個對象內容克隆一份時用到;
淺拷貝是在要複製一個對象的指針時用到。
親愛的讀者朋友,下面是我用於驗證的詳細代碼。對於驗證還能得出什麼結論,我希望朋友們能自己多多發掘一下。這裏只做以上幾點總結。對於本文有任何疑問請與我聯繫,歡迎指出本文不足的地方,謝謝!
#import<Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
@autoreleasepool {
//第一種:非容器類不可變對象
NSString *str1=@"one day";
printf("\n初始化賦值引用計數爲::::%lu",str1.retainCount);
NSString *strCopy1=[str1 retain];
printf("\n繼續retain引用計數爲:::%lu",str1.retainCount);
NSString *strCopy2=[str1 copy];
printf("\n繼續copy後引用計數爲::::%lu",str1.retainCount);
NSString *strCopy3=[str1 mutableCopy];
printf("\n繼續mutableCopy後爲:::%lu\n",str1.retainCount);
printf("\n非容器類不可變對象\n原始地址::::::::::%p",str1);
printf("\nretain複製::::::
printf("\ncopy複製::::::::::%p",strCopy2);
printf("\nmutableCopy複製:::%p",strCopy3);
//這裏說明該類型不存在引用計數的概念
// 初始化賦值引用計數爲:18446744073709551615
// 繼續retain引用計數爲:18446744073709551615
// 繼續copy後引用計數爲:18446744073709551615
// 繼續mutableCopy後爲:18446744073709551615
//非容器類不可變對象
//原始地址::::::::::0x1000033d0
//retain複製::::::::0x1000033d0//淺複製
//copy複製::::::::::0x1000033d0//淺複製
//mutableCopy複製:::0x10010c420//深複製
printf("\n");
//第二種:容器類不可變數組
NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
printf("\n初始化賦值引用計數爲::::::::::::%lu",array1.retainCount);
NSArray *arrayCopy1 = [array1 retain];
printf("\n繼續retain後引用計數爲:::::::::%lu",array1.retainCount);
NSArray *arrayCopy2 = [array1 copy];
printf("\n繼續copy後引用計數爲:::::::::::%lu",array1.retainCount);
NSArray *arrayCopy3 = [array1 mutableCopy];
printf("\n繼續mutableCopy後引用計數爲::::%lu\n",array1.retainCount);
printf("\n容器類不可變數組\n原始地址::::::::::%p\t\t%p",array1,[array1 objectAtIndex:1]);
printf("\nretain複製::::::::%p\t%p",arrayCopy1,[arrayCopy1 objectAtIndex:1]);
printf("\ncopy複製::::::::::%p\t%p",arrayCopy2,[arrayCopy2 objectAtIndex:1]);
printf("\nmutableCopy複製:::%p\t%p",arrayCopy3,[arrayCopy3 objectAtIndex:1]);
//初始化賦值引用計數爲::::::::::::1
//繼續retain後引用計數爲:::::::::2
//繼續copy後引用計數爲:::::::::::3
//繼續mutableCopy後引用計數爲::::3
//容器類不可變數組
//原始地址::::::::::0x10010c6b0 0x100003410
//retain複製::::::::0x10010c6b0 0x100003410//淺複製
//copy複製::::::::::0x10010c6b0 0x100003410//淺複製
//mutableCopy複製:::0x10010c760 0x100003410//深複製
printf("\n");
//第三種:非容器類可變對象
NSMutableString *str2=[NSMutableString stringWithString:@"two day"];
printf("\n初始化賦值引用計數爲::::::::::::%lu",str2.retainCount);
NSMutableString *strCpy1=[str2 retain];
printf("\n繼續retain後引用計數爲:::::::::%lu",str2.retainCount);
NSMutableString *strCpy2=[str2 copy];
printf("\n繼續copy後引用計數爲:::::::::::%lu",str2.retainCount);
NSMutableString *strCpy3=[str2 mutableCopy];
printf("\n繼續mutableCopy後引用計數爲::::%lu\n",str2.retainCount);
printf("\n非容器類可變對象\n原始地址::::::::::%p",str2);
printf("\nretin複製::::::::%p",strCpy1);
printf("\ncopy複製::::::::::%p",strCpy2);
printf("\nmutableCopy複製:::%p",strCpy3);
//初始化賦值引用計數爲::::::::::::1
//繼續retain後引用計數爲:::::::::2
//繼續copy後引用計數爲:::::::::::2
//繼續mutableCopy後引用計數爲::::2
//非容器類可變對象
//原始地址::::::::::0x10010c560
//retain複製::::::::0x10010c560//淺複製
//copy複製::::::::::0x100102720//深複製
//mutableCopy複製:::0x10010c880//深複製
printf("\n");
//第四種:容器類可變數組
NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];
printf("\n初始化賦值引用計數爲::::::::::%lu",array2.retainCount);
NSMutableArray *arrayCpy1 = [array2 retain];
printf("\n繼續retain後引用計數爲:::::::%lu",array2.retainCount);
NSMutableArray *arrayCpy2=[array2 copy];
printf("\n繼續copy後引用計數爲:::::::::%lu",array2.retainCount);
NSMutableArray *arrayCpy3 = [array2 mutableCopy];
printf("\n繼續mutableCopy後引用計數爲::%lu\n",array2.retainCount);
printf("\n容器類可變數組\n原始地址:::::::::::%p\t%p",array2,[array2 objectAtIndex:1]);
printf("\nretain複製:::::::::%p\t%p",arrayCpy1,[arrayCpy1 objectAtIndex:1]);
printf("\ncopy複製:::::::::::%p\t%p",arrayCpy2,[arrayCpy2 objectAtIndex:1]);
printf("\nnmutableCopy複製:::%p\t%p",arrayCpy3,[arrayCpy3 objectAtIndex:1]);
//初始化賦值引用計數爲::::::::::1
//繼續retain後引用計數爲:::::::2
//繼續copy後引用計數爲:::::::::2
//繼續mutableCopy後引用計數爲::2
//容器類可變數組
//原始地址:::::::::::0x10010e6c0 0x1000034b0
//retain複製:::::::::0x10010e6c0 0x1000034b0//淺複製
//copy複製:::::::::::0x10010e790 0x1000034b0//深複製
//nmutableCopy複製:::0x10010e7c0 0x1000034b0//深複製
}
return 0;
}