首先分類一下:(1) 非容器 , 容器 : (2) 不可變對(duì)象,可變對(duì)象
\1. 非容器不可變對(duì)象丐箩,比如NSString
2.非容器可變對(duì)象:比如NSMutableString
3.容器類不可變對(duì)象: 比如NSArray
4.容器類可變對(duì)象: 比如NSMutableArray
在觀察深淺拷貝之前先得了解一下retain茅撞,copy和mutableCopy的特點(diǎn)顽爹,特點(diǎn)如下:
1.retain:始終是淺復(fù)制七咧。引用計(jì)數(shù)每次加一。返回對(duì)象是否可變與被復(fù)制的對(duì)象保持一致猾蒂。(所以后面不再舉例,需要測(cè)試的在手動(dòng)管理上)
2.copy:對(duì)于可變對(duì)象為深復(fù)制悠夯,引用計(jì)數(shù)不改變;對(duì)于不可變對(duì)象是淺復(fù)制, 引用計(jì)數(shù)每次加一竟稳。始終返回一個(gè)不可變對(duì)象属桦。
3.mutableCopy:始終是深復(fù)制,引用計(jì)數(shù)不改變他爸。始終返回一個(gè)可變對(duì)象聂宾。
下面把容器非容器,可變非可變結(jié)合著retain,copy,mutableCopy來仔細(xì)的分析一下OC中得深淺拷貝诊笤,代碼走起:
1.非容器 + 不可變對(duì)象 + retain + copy + mutableCopy
NSString *str = @"InteviewTestCode";
//把str通過copy的方式把值賦給str2
NSString *str2 = [str copy];
//把str通過mutableCopy的方式把值賦給str3
NSString *str3 = [str mutableCopy];
//分別輸出每個(gè)字符串的內(nèi)存地址
NSLog(@" str-p = %p", str);
NSLog(@"str2-p = %p", str2);
NSLog(@"str3-p = %p", str3);
代碼運(yùn)行結(jié)果分析:
2017-02-17 09:57:02.690 InteviewTestCode[18890:507384] str-p = 0x10d185110
2017-02-17 09:57:02.690 InteviewTestCode[18890:507384] str2-p = 0x10d185110
2017-02-17 09:57:02.691 InteviewTestCode[18890:507384] str3-p = 0x60800006fd80
\1. 對(duì)于非容器類的不可變對(duì)象retain和copy為淺拷貝系谐,mutableCopy為深拷貝
淺拷貝獲得的對(duì)象的地址和原有對(duì)象的地址一致
3.而深拷貝返回新的內(nèi)存地址,并且返回的對(duì)象為可變對(duì)象
2.非容器 + 可變對(duì)象 + retain + copy + mutableCopy
接下來我們來測(cè)試下非容器類的可變對(duì)象的深淺拷貝
代碼如下:
Objective-C
//2.非容器 + 可變對(duì)象 + retain + copy + mutableCopy
NSMutableString *s = [NSMutableString stringWithFormat:@"InteviewTestCode"];
//把s通過copy的方式把值賦給s2;
NSMutableString *s2 = [s copy];
//把s通過mutableCopy的方式把值賦給s3
NSMutableString *s3 = [s mutableCopy];
?
//打印每個(gè)非容器類可變對(duì)象的地址
NSLog(@" s_p = %p", s);
NSLog(@"s2_p = %p", s2);
NSLog(@"s3_p = %p", s3);
?```
運(yùn)行結(jié)果分析:
InteviewTestCode[18890:507384] s_p = 0x600000071580
2017-02-17 09:57:02.692 InteviewTestCode[18890:507384] s2_p = 0xa6968736164756c7
2017-02-17 09:57:02.692 InteviewTestCode[18890:507384] s3_p = 0x600000071280
1.retian對(duì)對(duì)可變對(duì)象為淺拷貝
2.copy對(duì)可變對(duì)象非容器類為深拷貝
3.mutableCopy對(duì)可變非容器類為深拷貝
**3.容器類 + 非可變對(duì)象 + retain + copy + mutableCopy**
容器類的非可變對(duì)象進(jìn)行測(cè)試:容器需要特別注意的是容器本身和容器內(nèi)的對(duì)象分別是什么結(jié)果讨跟,(1)從容器對(duì)象看而言是容器的深拷貝, (2)但從輸出容器中的元素是容器的淺拷貝(所以下面代碼并不是容器真正意義上的的完全拷貝,本文最后做介紹)纪他。
NSMutableString *string = [NSMutableString stringWithFormat:@"ludashi"];
//第二種:容器類不可變對(duì)象拷貝
NSArray *array = [NSArray arrayWithObjects:string, @"b", nil];
?
//把a(bǔ)rray通過copy的方式把值賦給array2
NSArray *array2 = [array copy];
?
//把a(bǔ)rray通過mutableCopy方式把值賦給array3
NSArray *array3 = [array mutableCopy];
?
//分別輸出每個(gè)地址
NSLog(@"分別輸出每個(gè)地址");
NSLog(@" array_p = %p", array);
NSLog(@"array2_p = %p", array2);
NSLog(@"array3_p = %p", array3);
?
//分別輸出每個(gè)地址
NSLog(@"分別輸出拷貝后數(shù)組中第一個(gè)元素的地址");
NSLog(@" array_p[0] = %p", array[0]);
NSLog(@"array2_p[0] = %p", array2[0]);
NSLog(@"array3_p[0] = %p", array3[0]);
運(yùn)行結(jié)果:
2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] 分別輸出每個(gè)地址
2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] array_p = 0x608000036600
2017-02-17 10:29:18.065 InteviewTestCode[18973:524282] array2_p = 0x608000036600
2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array3_p = 0x6080000498d0
2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] 分別輸出拷貝后數(shù)組中第一個(gè)元素的地址
2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array_p[0] = 0x608000074340
2017-02-17 10:29:18.066 InteviewTestCode[18973:524282] array2_p[0] = 0x608000074340
2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] array3_p[0] = 0x608000074340
容器類的非可變對(duì)象:
copy拷貝獲得的對(duì)象的地址和原有對(duì)象的地址一致
2.而mutableCopy拷貝返回新的內(nèi)存地址,并且返回的對(duì)象為可變對(duì)象
3.而容器內(nèi)對(duì)象的地址總是一樣的,不受copy,mutableCopy影響
**4.容器類 + 可變對(duì)象 + retain + copy + mutableCopy**
下面對(duì)容器類的可變對(duì)象進(jìn)行測(cè)試晾匠,copy和mutableCopy對(duì)于容器本身是深拷貝茶袒,原因是返回了一個(gè)新的容器地址,但對(duì)于容器中的元素仍然是淺拷貝混聊。
代碼如下:
//第四種:容器類的可變對(duì)象的拷貝弹谁,用NSMutableArray來實(shí)現(xiàn)
NSMutableArray *m_array = [NSMutableArray arrayWithObjects:string, nil];
NSMutableArray *m_array2 = [m_array copy];
//把m_array通過mytableCopy把值賦給m_array3
NSMutableArray *m_array3 = [m_array mutableCopy];
?
//打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址
NSLog(@"打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址");
NSLog(@" m_array_p = %p", m_array);
NSLog(@"m_array_p2 = %p", m_array2);
NSLog(@"m_array_p3 = %p", m_array3);
?
//打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?/p>
NSLog(@"打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?);
NSLog(@" m_array_p[0] = %p", m_array[0]);
NSLog(@"m_array_p2[0] = %p", m_array2[0]);
NSLog(@"m_array_p3[0] = %p", m_array3[0]);
運(yùn)行結(jié)果:
2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] 打印輸出每個(gè)可變?nèi)萜鲗?duì)象的地址
2017-02-17 10:29:18.078 InteviewTestCode[18973:524282] m_array_p = 0x608000049780
2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p2 = 0x60800001a0a0
2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p3 = 0x608000049300
2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] 打印輸出每個(gè)可變?nèi)萜髦性氐牡刂?/p>
2017-02-17 10:29:18.079 InteviewTestCode[18973:524282] m_array_p[0] = 0x608000074340
2017-02-17 10:29:18.080 InteviewTestCode[18973:524282] m_array_p2[0] = 0x608000074340
2017-02-17 10:29:18.080 InteviewTestCode[18973:524282] m_array_p3[0] = 0x608000074340
容器類的可變對(duì)象:
1.copy:對(duì)于可變對(duì)象為深復(fù)制,引用計(jì)數(shù)不改變;對(duì)于不可變對(duì)象是淺復(fù)制句喜, 引用計(jì)數(shù)每次加一。始終返回一個(gè)不可變對(duì)象沟于。
2.mutableCopy:始終是深復(fù)制咳胃,引用計(jì)數(shù)不改變。始終返回一個(gè)可變對(duì)象旷太。
**5.自定義類對(duì)象之間的深淺拷貝問題**
在Objective-C中并不是所有的類都支持拷貝展懈;只有遵循NSCopying協(xié)議的類销睁,才支持copy拷貝,只有遵循NSMutableCopying協(xié)議的類存崖,才支持mutableCopy拷貝冻记。如果沒有遵循拷貝協(xié)議,拷貝時(shí)會(huì)出錯(cuò)来惧。
如果我們想再我們自定義的類中支持copy和mutableCopy那么我們就需要使我們定義的類遵循NSCopying和NSMutableCopying協(xié)議冗栗,代碼如下:
@interface CopyTestObj : NSObject<NSCopying,NSMutableCopying>
@end
然后再重寫-(id) copyWithZone : (NSZone *) zone 和 -(id)mutableCopyWithZone : (NSZone *) zone
重寫-(id) copyWithZone :(NSZone *)zone方法如下
//淺拷貝
-(id) copyWithZone:(NSZone *) zone {
CopyTestObj *test = [[CopyTestObj allocWithZone : zone] init];
return test;
}
//深拷貝
-(id) mutableCopyWithZone : (NSZone *) zone {
CopyTestObj *test = [[CopyTestObj allocWithZone : zone] init];
//區(qū)別:對(duì)屬性也進(jìn)行復(fù)制
test.typeStr = self.typeStr;
return test;
}
6.我們?nèi)绾螌?shí)現(xiàn)容器中的完全拷貝呢?上面沒有考慮到容器中元素拷貝的問題供搀,下面進(jìn)行代碼補(bǔ)充
首先:遵循NSCoder協(xié)議
@interface CopyTestObj : NSCoder<NSCopying,NSMutableCopying>
代碼如下:
//新建一個(gè)測(cè)試字符串
NSMutableString * str = [NSMutableString stringWithFormat:@"ludashi__"];
//新建一個(gè)測(cè)試字典
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:1];
[dic setObject:str forKey:@"key1"];
?
//把字典存入數(shù)組中
NSMutableArray *oldArray = [NSMutableArray arrayWithObject:dic];
?
//用就得數(shù)組生成新的數(shù)組
NSMutableArray *newArray = [NSMutableArray arrayWithArray:oldArray];
?
//用copyItems拷貝數(shù)組中的元素
NSMutableArray *copyItems = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];
?
//把數(shù)組歸檔成一個(gè)NSData,然后再實(shí)現(xiàn)完全拷貝
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:oldArray];
NSMutableArray *multable = [NSKeyedUnarchiver unarchiveObjectWithData:data];
?
//往字典中加入新的值
[dic setObject:@"new_value1" forKey:@"key2"];
//改變str的值
[str appendString:@"update"];
NSLog(@"%@", oldArray);
NSLog(@"%@", newArray);
NSLog(@"%@", copyItems);
NSLog(@"%@", multable);
?
//每個(gè)數(shù)組的地址為:
NSLog(@"%p", oldArray);
NSLog(@"%p", newArray);
NSLog(@"%p", copyItems);
NSLog(@"%p", multable);
運(yùn)行結(jié)果:
2014-08-13 16:33:00.752 OC6-1[3942:303] (
{
key1 = "ludashi__update";
key2 = "new_value1";
}
)
2014-08-13 16:33:00.753 OC6-1[3942:303] (
{
key1 = "ludashi__update";
key2 = "new_value1";
}
)
2014-08-13 16:33:00.753 OC6-1[3942:303] (
{
key1 = "ludashi__update";
}
)
2014-08-13 16:33:00.753 OC6-1[3942:303] (
{
key1 = "ludashi__";
}
)
2014-08-13 16:33:00.754 OC6-1[3942:303] 0x100204560
2014-08-13 16:33:00.754 OC6-1[3942:303] 0x1002046d0
2014-08-13 16:33:00.754 OC6-1[3942:303] 0x1002047c0
2014-08-13 16:33:00.755 OC6-1[3942:303] 0x100406610
可以看出,通過數(shù)組歸檔可以實(shí)現(xiàn)容器深復(fù)制 和 容器里的 對(duì)象 也同時(shí)深復(fù)制(地址不同)