深拷贝和浅拷贝都是针对复合类型(对象,结构体指针)
浅拷贝
新对象是拷贝了原对象的地址(引用),指向的还是原来的对象,修改其中一个另一个也会跟着改变
图解:
深拷贝
新对象是开辟了了一块新的地址,然后把原对象的值赋值给新对象,修改任意一个不会影响另一个对象(这也是区分浅拷贝和深拷贝地方)
图解:

IOS下的拷贝有copy
和mutableCopy
两个方法
需要分别遵守两个协议NSCopying
,NSMutableCopying
然后实现:
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
//...
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
//...
}
不然直接调用会crash,好在常用的字符串,数组等 苹果帮我门实现了这两个协议.
copy
和mutableCopy
分为可变和不可变,容器和非容器的情况
1.1 不可变 - 非容器类
NSString *str1 = @"非容器类不可变";//常量字符串
NSString *str2 = str1.copy;//浅拷贝-常量字符串
NSString *str3 = str1.mutableCopy;//深拷贝-可变字符串
NSLog(@"str1:%p,class:%@",str1,[str1 class]);
NSLog(@"str2:%p,class:%@",str2,[str2 class]);
NSLog(@"str3:%p,class:%@",str3,[str3 class]);
输出:
str1:0x100002040,class:__NSCFConstantString//常量不可变字符串
str2:0x100002040,class:__NSCFConstantString//常量不可变字符串
str3:0x102300100,class:__NSCFString//可变字符串
结论:
非容器-不可变对象 用copy的结果:发生浅拷贝,拷贝的对象不可变
非容器-不可变对象 用mutableCopy的结果:发生深拷贝,深拷贝的对象可变
1.2 可变-非容器类
NSMutableString *mutStr1 = [NSMutableString stringWithString:@"非容器类可变"];//可变字符
NSMutableString *mutStr2 = [mutStr1 copy];//深拷贝-可变字符串
NSMutableString *mutStr3 = [mutStr1 mutableCopy];//深拷贝-可变字符串
NSLog(@"mutStr1:%p,class:%@",mutStr1,[mutStr1 class]);
NSLog(@"mutStr2:%p,class:%@",mutStr2,[mutStr2 class]);
NSLog(@"mutStr3:%p,class:%@",mutStr3,[mutStr3 class]);
输出:
mutStr1:0x100602040,class:__NSCFString //深拷贝-可变
mutStr2:0x100601180,class:__NSCFString //深拷贝-可变
mutStr3:0x100600630,class:__NSCFString //深拷贝-可变
结论:
非容器-可变对象 调用copy 后发生深拷贝,拷贝的对象可变
非容器-可变对象 调用mutableCopy 后发生深拷贝,拷贝的对象可变
2.1容器类-不可变
NSArray *array1 = @[@"1",@"2",@"3"];//不可变数组
NSArray *array2 = array1.copy;//浅拷贝,不可变数组
NSArray *array3 = array1.mutableCopy;//深拷贝,可变数组
NSLog(@"array1:%p,class:%@",array1,[array1 class]);
NSLog(@"array2:%p,class:%@",array2,[array2 class]);
NSLog(@"array3:%p,class:%@",array3,[array3 class]);
输出:
array1:0x100748b00,class:__NSArrayI //浅拷贝-不可变
array2:0x100748b00,class:__NSArrayI //浅拷贝-不可变
array3:0x100748bd0,class:__NSArrayM //深拷贝-可变
2.1.1拷贝之后容器里的对象也会跟着变为对应的浅拷贝和深拷贝吗?
for (id item in array1) {
NSLog(@"array1-%p",item);
}
for (id item in array2) {
NSLog(@"array2-%p",item);
}
for (id item in array3) {
NSLog(@"array3-%p",item);
}
输出:
原对象
array1-0x100002048 //1
array1-0x100002068 //2
array1-0x100002088 //3
copy的对象
array2-0x100002048 //copy-1
array2-0x100002068 //copy-2
array2-0x100002088 //copy-3
mutableCopy的对象
array3-0x100002048 //mutableCopy-1
array3-0x100002068 //mutableCopy-2
array3-0x100002088 //mutableCopy-3
结论:
容器类-不可变对象:调用copy 发生浅拷贝,拷贝的对象不可变
容器类-不可变对象:调用mutableCopy 发生深拷贝,拷贝的对象可变
容器里的对象都是浅拷贝的
这不难理解,对象数组里存的本来就是对象的地址而不是对象本本身,浅拷贝本身就是数组的引用,深拷贝开辟一块新地址后也是把原来数组中元素的地址变量赋值到新数组
示例:对象数组
[
0x100002048,
0x100002068,
0x100002088
]
2.2容器类-可变
NSMutableArray *mutArray1 = [NSMutableArray arrayWithArray:@[@"1",@"2",@"3"]];//可变
NSMutableArray *mutArray2 = mutArray1.copy;//浅拷贝-不可变
NSMutableArray *mutArray3 = mutArray1.mutableCopy;//深拷贝-可变
NSLog(@"mutArray1:%p,class:%@",mutArray1,[mutArray1 class]);
NSLog(@"mutArray2:%p,class:%@",mutArray2,[mutArray2 class]);
NSLog(@"mutArray3:%p,class:%@",mutArray3,[mutArray3 class]);
输出:
mutArray1:0x102d00200,class:__NSArrayM //深拷贝-可变
mutArray2:0x102d00310,class:__NSArrayI //深拷贝-不可变
mutArray3:0x102d00350,class:__NSArrayM //深拷贝-可变
结论:
容器类-可变:调用copy深拷贝 拷贝后产生的对象不可变
容器类-可变:调用mutableCopy深拷贝 拷贝后产生的对象可变
容器里的元素当然也是浅拷贝的,验证方法和2.1.1是一样的
3 自定义对象
苹果只是部分类实现了copy协议,自定义的对象要调用copy和mutableCopy必须实现copy的两个协议:
最后看这张表:

- 不可变对象会发生浅拷贝,可变对象是深拷贝;
- mutableCopy一定是深拷贝,并且产生可变对象
- 这只是苹果苹果实现copyWithZone和mutableCopyWithZone的规律,自定义的行为,完全取决于这两个方法的实现.
网友评论