淺拷貝
對(duì)內(nèi)存地址的復(fù)制,沒有對(duì)內(nèi)存空間復(fù)制翁狐,讓目標(biāo)對(duì)象指針和源對(duì)象指向同一塊內(nèi)存空間类溢。
增加被拷貝對(duì)象引用計(jì)數(shù),未發(fā)生新的內(nèi)存分配露懒。
深拷貝
讓目標(biāo)對(duì)象和源對(duì)象指針分別指向內(nèi)容相同的內(nèi)存空間闯冷。
不會(huì)增加被拷貝對(duì)象的引用計(jì)數(shù),產(chǎn)生新的內(nèi)存分配隐锭。
1窃躲、非容器對(duì)象的深拷貝和淺拷貝
以NSString 和 NSMutableString為例
NSString *str1 = @"str1";
NSString *str1Copy = [str1 copy];
NSString *str1mutCopy = [str1 mutableCopy];
NSMutableString *mutstr1Copy = [str1 copy];
NSMutableString *mutstr1mutCopy = [str1 mutableCopy];
NSLog(@"str1 = %@, address = %p",str1,str1);
NSLog(@"str1Copy = %@, address = %p",str1Copy,str1Copy);
NSLog(@"str1mutCopy = %@, address = %p",str1mutCopy,str1mutCopy);
NSLog(@"mutstr1Copy = %@, address = %p",mutstr1Copy,mutstr1Copy);
NSLog(@"mutstr1mutCopy = %@, address = %p",mutstr1mutCopy,mutstr1mutCopy);
NSMutableString *mutstr2 = [NSMutableString stringWithString:@"mutstrhello2"];
NSMutableString *mutstr2Copy = [mutstr2 copy];
NSMutableString *mutstr2mutCopy = [mutstr2 mutableCopy];
NSString *str2Copy = [mutstr2 copy];
NSString *str2mutCopy = [mutstr2 mutableCopy];
NSLog(@"mutstr2 = %@, address = %p",mutstr2,mutstr2);
NSLog(@"mutstr2Copy = %@, address = %p",mutstr2Copy,mutstr2Copy);
NSLog(@"mutstr2mutCopy = %@, address = %p",mutstr2mutCopy,mutstr2mutCopy);
NSLog(@"str2Copy = %@, address = %p",str2Copy,str2Copy);
NSLog(@"str2mutCopy = %@, address = %p",str2mutCopy,str2mutCopy);
輸出結(jié)果
str1 = str1, address = 0x10c44f2e8
str1Copy = str1, address = 0x10c44f2e8
str1mutCopy = str1, address = 0x6000025d2a30
mutstr1Copy = str1, address = 0x10c44f2e8
mutstr1mutCopy = str1, address = 0x6000025d2a60
mutstr2 = mutstrhello2, address = 0x6000025e84b0
mutstr2Copy = mutstrhello2, address = 0x600002b95000
mutstr2mutCopy = mutstrhello2, address = 0x6000025e8300
str2Copy = mutstrhello2, address = 0x600002b94f80
str2mutCopy = mutstrhello2, address = 0x6000025e82d0
可以看到結(jié)論如下:
可變對(duì)象copy/mutablecopy都是深拷貝。
不可變對(duì)象的copy是淺拷貝钦睡。
??????copy方法返回的都是不可變對(duì)象蒂窒,可變對(duì)象經(jīng)過copy后不可變。
2荞怒、自定義類對(duì)象的深淺拷貝
必須實(shí)現(xiàn)NSCopying協(xié)議
@interface TestModel : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSMutableString *mutname;
@end
@implementation TestModel
- (id)copyWithZone:(NSZone *)zone {
TestModel *t = [[TestModel allocWithZone:zone]init];
t.name = self.name;
t.mutname = self.mutname;
return t;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
TestModel *t = [[TestModel allocWithZone:zone]init];
t.name = self.name;
t.mutname = self.mutname;
return t;
}
@end
TestModel *t1 = [[TestModel alloc]init];
t1.name = @"test1";
t1.mutname = [NSMutableString stringWithString:@"mut111"];
TestModel *t1Copy = [t1 copy];
TestModel *t1Mutcopy = [t1 mutableCopy];
NSLog(@"t1 = %p, t1.name = %p,t1.mutname = %p",t1, t1.name,t1.mutname);
NSLog(@"t1Copy = %p, t1Copy.name = %p,t1Copy.mutname = %p",t1Copy, t1Copy.name,t1Copy.mutname);
NSLog(@"t1Mutcopy = %p, t1Mutcopy.name = %p,t1Mutcopy.mutname = %p",t1Mutcopy, t1Mutcopy.name,t1Mutcopy.mutname);
輸出
t1 = 0x600002f61940, t1.name = 0x104fc52f0, t1.mutname = 0x600002116250
t1Copy = 0x600002f61980, t1Copy.name = 0x104fc52f0, t1Copy.mutname = 0x600002116250
t1Mutcopy = 0x600002f619a0, t1Mutcopy.name = 0x104fc52f0, t1Mutcopy.mutname = 0x600002116250
實(shí)驗(yàn)可知自定義類的copy和mutablecopy洒琢,都是深拷貝,但是自定義類屬性是淺拷貝褐桌,也就是只是復(fù)制了屬性的引用衰抑,可以和容器類元素一起了解。
2荧嵌、容器類型
以NSArray和NSMutableArray為例
NSString *tmp = @"str1";
NSArray *arr1 = @[tmp,@"a",@"b",@"c"];
NSArray *arr1Copy = [arr1 copy];
NSArray *arr1Mutcopy = [arr1 mutableCopy];
NSMutableArray *mutarr1Copy = [arr1 copy];
NSMutableArray *mutarr1Mutcopy = [arr1 mutableCopy];
NSLog(@"arr1 = %p, arr1[0] = %p",arr1,arr1[0]);
NSLog(@"arr1Copy = %p, arr1Copy[0] = %p",arr1Copy,arr1Copy[0]);
NSLog(@"arr1Mutcopy = %p, arr1Mutcopy[0] = %p",arr1Mutcopy,arr1Mutcopy[0]);
NSLog(@"mutarr1Copy = %p, mutarr1Copy[0] = %p",mutarr1Copy,mutarr1Copy[0]);
NSLog(@"mutarr1Mutcopy = %p, mutarr1Mutcopy[0] = %p",mutarr1Mutcopy,mutarr1Mutcopy[0]);
NSMutableArray *mutarr2 = [NSMutableArray arrayWithObjects:tmp,@"muta",@"mutb",@"mutc", nil];
NSMutableArray *mutarr2Copy = [mutarr2 copy];
NSMutableArray *mutarr2Mutcopy = [mutarr2 mutableCopy];
NSArray *arr2Copy = [arr1 copy];
NSArray *arr2Mutcopy = [arr1 mutableCopy];
NSLog(@"mutarr2 = %p, mutarr2[0] = %p",mutarr2,mutarr2[0]);
NSLog(@"mutarr2Copy = %p, mutarr2Copy[0] = %p",mutarr2Copy,mutarr2Copy[0]);
NSLog(@"mutarr2Mutcopy = %p, mutarr2Mutcopy[0] = %p",mutarr2Mutcopy,mutarr2Mutcopy[0]);
NSLog(@"arr2Copy = %p, arr2Copy[0] = %p",arr2Copy,arr2Copy[0]);
NSLog(@"arr2Mutcopy = %p, arr2Mutcopy[0] = %p",arr2Mutcopy,arr2Mutcopy[0]);
輸出結(jié)果
arr1 = 0x600000870660, arr1[0] = 0x10e7f52f8
arr1Copy = 0x600000870660, arr1Copy[0] = 0x10e7f52f8
arr1Mutcopy = 0x600000870540, arr1Mutcopy[0] = 0x10e7f52f8
mutarr1Copy = 0x600000870660, mutarr1Copy[0] = 0x10e7f52f8
mutarr1Mutcopy = 0x6000008707e0, mutarr1Mutcopy[0] = 0x10e7f52f8
mutarr2 = 0x6000008707b0, mutarr2[0] = 0x10e7f52f8
mutarr2Copy = 0x600000870930, mutarr2Copy[0] = 0x10e7f52f8
mutarr2Mutcopy = 0x6000008705d0, mutarr2Mutcopy[0] = 0x10e7f52f8
arr2Copy = 0x600000870660, arr2Copy[0] = 0x10e7f52f8
arr2Mutcopy = 0x6000008708d0, arr2Mutcopy[0] = 0x10e7f52f8
對(duì)于系統(tǒng)容器(數(shù)組/集合等)而言呛踊,整個(gè)容器符合非容器類深淺拷貝的規(guī)律。
但容器內(nèi)的元素始終是淺拷貝啦撮,容器元素的地址都沒有變化谭网。數(shù)組中的元素實(shí)際上是對(duì)象的引用,數(shù)組內(nèi)存儲(chǔ)的元素實(shí)際上是指向?qū)ο蟮囊迷叽海皇菍?duì)象本身愉择。當(dāng)我們將一個(gè)對(duì)象添加到數(shù)組中,實(shí)際上是將該對(duì)象的引用存儲(chǔ)在數(shù)組對(duì)應(yīng)的位置上。
示例:
NSMutableString *str1 = [NSMutableString stringWithString:@"Hello"];
NSString *str2 = @"oc";
NSArray *arr = @[str1, str2];
NSLog(@"arr = %@",arr);
[str1 appendString:@"123"];
NSLog(@"new arr = %@",arr);
輸出
arr = (
Hello,
oc
)
new arr = (
Hello123,
oc
)
??:使用NSMutableString 拼接是為了確保地址不變锥涕,如果是NSString衷戈,重新賦,相當(dāng)于重新初始化层坠,會(huì)生成新的地址殖妇。
3、如何實(shí)現(xiàn)完全深拷貝
1窿春、使用copyItems
TestModel *t1 = [[TestModel alloc]init];
t1.name = @"test1";
NSArray *arr = @[t1];
NSArray *copyArray = [arr copy];
NSArray *mutCopyArray = [arr mutableCopy];
NSArray *newArr = [[NSArray alloc]initWithArray:arr copyItems:YES];
NSLog(@"arr = %p, arr[0] = %p",arr,arr[0]);
NSLog(@"copyArray = %p, copyArray[0] = %p",copyArray,copyArray[0]);
NSLog(@"mutCopyArray = %p, mutCopyArray[0] = %p",mutCopyArray,mutCopyArray[0]);
NSLog(@"newArr = %p, newArr[0] = %p",newArr,newArr[0]);
輸出
arr = 0x6000020a8270, arr[0] = 0x6000022bf1e0
copyArray = 0x6000020a8270, copyArray[0] = 0x6000022bf1e0
mutCopyArray = 0x600002cf7300, mutCopyArray[0] = 0x6000022bf1e0
newArr = 0x6000020a8250, newArr[0] = 0x6000022bf200
如果容器內(nèi)對(duì)象中的元素是非容器類拉一,可以使用copyItems進(jìn)行完全深拷貝,根據(jù)官方文檔對(duì)copyItems的解釋
copyItems官方文檔當(dāng)YES時(shí)旧乞,可以使第一層元素實(shí)現(xiàn)深拷貝蔚润,更深層的還是使用對(duì)象的引用。
2尺栖、遞歸復(fù)制屬性
@interface TestModel : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSMutableString *mutname;
@end
@implementation TestModel
- (id)copyWithZone:(NSZone *)zone {
TestModel *t = [[TestModel allocWithZone:zone]init];
t.name = [self.name copy];
t.mutname = [self.mutname mutableCopy];
return t;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
TestModel *t = [[TestModel allocWithZone:zone]init];
t.name = [self.name copy];
t.mutname = [self.mutname mutableCopy];
return t;
}
@end
TestModel *t1 = [[TestModel alloc]init];
t1.name = @"test1";
t1.mutname = [NSMutableString stringWithString:@"mut111"];
TestModel *t1Copy = [t1 copy];
TestModel *t1Mutcopy = [t1 mutableCopy];
NSLog(@"t1 = %p, t1.name = %p,t1.mutname = %p",t1, t1.name,t1.mutname);
NSLog(@"t1Copy = %p, t1Copy.name = %p,t1Copy.mutname = %p",t1Copy, t1Copy.name,t1Copy.mutname);
NSLog(@"t1Mutcopy = %p, t1Mutcopy.name = %p,t1Mutcopy.mutname = %p",t1Mutcopy, t1Mutcopy.name,t1Mutcopy.mutname);
輸出:
t1 = 0x6000019c25c0, t1.name = 0x104ec52f0,t1.mutname = 0x6000017b64c0
t1Copy = 0x6000019c2600, t1Copy.name = 0x104ec52f0,t1Copy.mutname = 0x6000017b6580
t1Mutcopy = 0x6000019c2640, t1Mutcopy.name = 0x104ec52f0,t1Mutcopy.mutname = 0x6000017b63d0
3嫡纠、解檔歸檔
若是自定義對(duì)象,必須遵循NSCoding協(xié)議
NSArray *arr = @[@"ceshi shu"];
NSArray *copyArr = [arr copy];
NSArray *mutCopyArr = [arr mutableCopy];
// 使用歸檔和解檔來創(chuàng)建數(shù)組的深拷貝
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
NSArray *newArr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"arr = %p, arr[0] = %p", arr, arr[0]);
NSLog(@"copyArr = %p, copyArr[0] = %p", copyArr, copyArr[0]);
NSLog(@"mutCopyArr = %p, mutCopyArr[0] = %p", mutCopyArr, mutCopyArr[0]);
NSLog(@"newArr = %p, newArr[0] = %p", newArr, newArr[0]);
輸出:
arr = 0x600000978260, arr[0] = 0x10d44c300
copyArr = 0x600000978260, copyArr[0] = 0x10d44c300
mutCopyArr = 0x600000509b60, mutCopyArr[0] = 0x10d44c300
newArr = 0x6000009782e0, newArr[0] = 0x8b27a7029db7aeb2