Objective-C 之深拷贝和浅拷贝

3月箴言

人的思想是了不起的,只要专注于某一项事业,就一定会做出使自己感到吃惊的成绩来。—— 马克·吐温

1、iOS中关于深拷贝和浅拷贝的概念

浅拷贝:浅拷贝并不拷贝对象本身,只是对指向对象的指针进行拷贝
深拷贝:直接拷贝对象到内存中一块区域,然后把新对象的指针指向这块内存

在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。如果要遵循NSCopying协议,那么必须实现copyWithZone方法。如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。

2、可变对象和不可变对象调用深拷贝和浅拷贝方法的区别以及具体示例:

2.1非容器类不可变对象

- (void)immutableStrCopyAndMutCopy
{
NSString *immutableStr = @"不可变字符串";
NSMutableString *immutableStrCopy = [immutableStr copy];
NSMutableString *immutableStrMutCopy = [immutableStr mutableCopy];
// [immutableStrCopy appendString:@"22"];
[immutableStrMutCopy appendString:@""];
NSLog(@"immutableStrMutCopy = %@",immutableStrMutCopy);
/*
immutableStr_p = 0x107a58068 immutableStr = __NSCFConstantString
immutableStrCopy_p = 0x107a58068 immutableStrCopy = __NSCFConstantString,
immutableStrMutCopy_p = 0x6000034e07e0,immutableStrMutCopy= __NSCFString
__NSCFConstantString 表示对象存储在常量区,__NSCFString表示对象存储在堆上
*/
NSLog(@"\n immutableStr_p = %p immutableStr = %@ \n immutableStrCopy_p = %p immutableStrCopy = %@,\n immutableStrMutCopy_p = %p,immutableStrMutCopy= %@",immutableStr,[immutableStr class],immutableStrCopy,[immutableStrCopy class],immutableStrMutCopy,[immutableStrMutCopy class]); }

非容器类不可变对象 执行copy 和 mutbleCopy

结论:

对非容器类的不可变对象 执行copy 是浅拷贝,地址相同,返回的也是不可变对象
                                  执行mutableCopy 是深拷贝,地址不同,返回的是可变对象

2.2非容器类可变对象

- (void)mutableStrCopyAndMutCopy
{
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"可变字符串"]; NSMutableString *mutableStrCopy = [mutableStr copy];
//copy 之后 变为不可变对象,不可执行拼接操作,窒息该操作,直接崩溃!!
// [mutableStrCopy appendString:@"copy 之后拼接"];
NSMutableString *mutableStrMutCopy = [mutableStr mutableCopy];
[mutableStrMutCopy appendString:@"mutcopy"];
/*
mutableStr.p = 0x600001589230 mutableStr.class = __NSCFString mutableStr = 可变字符串
mutableStrCopy.p = 0x6000015890b0 mutableStrCopy.class = __NSCFString,mutableStrCopy = 可变字符串
mutableStrMutCopy.p = 0x6000015887b0,mutableStrMutCopy.class= __NSCFString,mutableStrMutCopy = 可变字符串mutcopy
*/
NSLog(@"\n mutableStr.p = %p mutableStr.class = %@ mutableStr = %@ \n mutableStrCopy.p = %p mutableStrCopy.class = %@,mutableStrCopy = %@\n mutableStrMutCopy.p = %p,mutableStrMutCopy.class= %@,mutableStrMutCopy = %@",mutableStr,[mutableStr class],mutableStr,mutableStrCopy,[mutableStrCopy class],mutableStrCopy,mutableStrMutCopy,[mutableStrMutCopy class],mutableStrMutCopy); }

非容器类可变对象执行 copy 和 mutableCopy

结论:
对于非容器类的可变对象 执行 copy 深拷贝,地址不同,返回的是不可变对象
                                  执行mutableCopy,深拷贝,地址不同,返回的是可变对象

2.3容器类不可变对象

- (void)imArrayCopyAndMutCopy
{
NSString *immutableStr = @"不可变对象";
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"可变对象兮"];
NSArray *imArray = [NSArray arrayWithObjects:immutableStr,mutableStr, nil];
NSArray *imArrayCopy = [imArray copy];
NSArray *imArrayMutCopy = [imArray mutableCopy];
/*
imArray.p = 0x60000259d960 imArray.class = __NSArrayI
imArrayCopy.p = 0x60000259d960 imArrayCopy.class = __NSArrayI
imArrayMutCopy.p = 0x600002b839f0,imArrayMutCopy.class= __NSArrayM
2019-03-03 12:13:35.401764+0800 MyNewTestDemo[13557:3186194] imArray ---tempStr.p = 0x1098d4088,tempStr = __NSCFConstantString,tempStr.class = 不可变对象
2019-03-03 12:13:35.401864+0800 MyNewTestDemo[13557:3186194] imArray ---tempStr.p = 0x600002b83b70,tempStr = __NSCFString,tempStr.class = 可变对象兮
2019-03-03 12:13:35.401945+0800 MyNewTestDemo[13557:3186194] imArrayCopy ---tempCopyStr.p = 0x1098d4088,tempCopyStr = __NSCFConstantString,tempCopyStr.class = 不可变对象
2019-03-03 12:13:35.402043+0800 MyNewTestDemo[13557:3186194] imArrayCopy ---tempCopyStr.p = 0x600002b83b70,tempCopyStr = __NSCFString,tempCopyStr.class = 可变对象兮
2019-03-03 12:13:35.402111+0800 MyNewTestDemo[13557:3186194] imArrayMutCopy ---tempMutCopyStr.p = 0x1098d4088,tempMutCopyStr = __NSCFConstantString,tempMutCopyStr.class = 不可变对象
2019-03-03 12:13:35.402171+0800 MyNewTestDemo[13557:3186194] imArrayMutCopy ---tempMutCopyStr.p = 0x600002b83b70,tempMutCopyStr = __NSCFString,tempMutCopyStr.class = 可变对象兮
*/
NSLog(@"\n imArray.p = %p imArray.class = %@ \n imArrayCopy.p = %p imArrayCopy.class = %@\n imArrayMutCopy.p = %p,imArrayMutCopy.class= %@",imArray,[imArray class],imArrayCopy,[imArrayCopy class],imArrayMutCopy,[imArrayMutCopy class]); for (id tempStr in imArray) {
NSLog(@"imArray ---tempStr.p = %p,tempStr = %@,tempStr.class = %@\n",tempStr,[tempStr class],tempStr);
}
for (id tempCopyStr in imArrayCopy) {
NSLog(@"imArrayCopy ---tempCopyStr.p = %p,tempCopyStr = %@,tempCopyStr.class = %@\n",tempCopyStr,[tempCopyStr class],tempCopyStr);
} for (id tempMutCopyStr in imArrayMutCopy) {
NSLog(@"imArrayMutCopy ---tempMutCopyStr.p = %p,tempMutCopyStr = %@,tempMutCopyStr.class = %@\n",tempMutCopyStr,[tempMutCopyStr class],tempMutCopyStr);
} }

容器类对象 copy或mutableCopy (本方法是针对数组)

结论:对于容器类的不可变对象 执行copy 对于容器来说是浅copy,地址相同,且返回的是不可变对象
                                           执行mutableCopy 对于容器来说是深拷贝,地址不同,且返回的是可变对象。
                                           对于容器内的对象(可变或不可变对象)而言,无论容器执行的是copy还是mutableCopy,这些对象执行的都是浅拷贝

2.4容器类可变对象

- (void)mutArrayCopyAndMutCopy
{
NSString *immutableStr = @"不可变对象";
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"可变对象兮"];
NSMutableArray *mutArray = [NSMutableArray arrayWithObjects:immutableStr,mutableStr, nil]; /*
mutArray.p = 0x600002c17000 mutArray.class = __NSArrayM
mutArray.copy.p = 0x60000221ace0 mutArray.copy.Class = __NSArrayI
mutArray.mutCopy.p = 0x600002c16fd0,mutArray.mutCopy.p= __NSArrayM
2019-03-03 12:24:00.751299+0800 MyNewTestDemo[13742:3202669] mutArray ---tempStr.p = 0x10ec73088,tempStr = __NSCFConstantString,tempStr.class = 不可变对象
2019-03-03 12:24:00.751410+0800 MyNewTestDemo[13742:3202669] mutArray ---tempStr.p = 0x600002c17330,tempStr = __NSCFString,tempStr.class = 可变对象兮
2019-03-03 12:24:00.751502+0800 MyNewTestDemo[13742:3202669] mutArray.copy ---tempCopyStr.p = 0x10ec73088,tempCopyStr = __NSCFConstantString,tempCopyStr.class = 不可变对象
2019-03-03 12:24:00.751594+0800 MyNewTestDemo[13742:3202669] mutArray.copy ---tempCopyStr.p = 0x600002c17330,tempCopyStr = __NSCFString,tempCopyStr.class = 可变对象兮
2019-03-03 12:24:00.751694+0800 MyNewTestDemo[13742:3202669] mutArray.mutCopy ---tempMutCopyStr.p = 0x10ec73088,tempMutCopyStr = __NSCFConstantString,tempMutCopyStr.class = 不可变对象
2019-03-03 12:24:00.751789+0800 MyNewTestDemo[13742:3202669] mutArray.mutCopy ---tempMutCopyStr.p = 0x600002c17330,tempMutCopyStr = __NSCFString,tempMutCopyStr.class = 可变对象兮
*/
NSLog(@"\n mutArray.p = %p mutArray.class = %@ \n mutArray.copy.p = %p mutArray.copy.Class = %@\n mutArray.mutCopy.p = %p,mutArray.mutCopy.p= %@",mutArray,[mutArray class],[mutArray copy],[[mutArray copy] class],[mutArray mutableCopy],[[mutArray mutableCopy] class]);
for (id tempStr in mutArray) {
NSLog(@"mutArray ---tempStr.p = %p,tempStr = %@,tempStr.class = %@\n",tempStr,[tempStr class],tempStr);
}
for (id tempCopyStr in [mutArray copy]) {
NSLog(@"mutArray.copy ---tempCopyStr.p = %p,tempCopyStr = %@,tempCopyStr.class = %@\n",tempCopyStr,[tempCopyStr class],tempCopyStr);
} for (id tempMutCopyStr in [mutArray mutableCopy]) {
NSLog(@"mutArray.mutCopy ---tempMutCopyStr.p = %p,tempMutCopyStr = %@,tempMutCopyStr.class = %@\n",tempMutCopyStr,[tempMutCopyStr class],tempMutCopyStr);
}
}

容器类可变对象 copy和mutableCopy (本方法是针对数组)

结论:对于容器类可变对象 执行copy,深拷贝,地址不同,返回的是不可变对象
                                     执行mutableCopy,深拷贝,地址不同,返回的是不可变对象
                                     容器内的对象(无论可变或不可变),均为浅拷贝(地址相同)

- (void)imDicCopyAndMutCopy
{
NSString *immutableStrOne = @"不可变对象1";
NSMutableString *mutableStrOne = [NSMutableString stringWithFormat:@"可变对象1"];
NSString *immutableStrTwo = @"不可变对象2";
NSMutableString *mutableStrTwo = [NSMutableString stringWithFormat:@"可变对象2"];
/*
immutableDic.p = 0x6000003d2400 immutableDic.class = __NSDictionaryI
immutableDic.copy.p = 0x6000003d2400 immutableDic.copy.class = __NSDictionaryI
immutableDic.mutcopy.p = 0x600002dc8e00,immutableDic.mutcopy.class= __NSDictionaryM
2019-03-03 12:37:08.098513+0800 MyNewTestDemo[13840:3214742] immutableDic ---key.p = 0x600002398e40,key.class = __NSCFString,key = 可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1
2019-03-03 12:37:08.098588+0800 MyNewTestDemo[13840:3214742] immutableDic ---key.p = 0x600002399260,key.class = __NSCFString,key = 可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.098698+0800 MyNewTestDemo[13840:3214742] immutableDic ---key.p = 0x105a20148,key.class = __NSCFConstantString,key = 不可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.098785+0800 MyNewTestDemo[13840:3214742] immutableDic ---key.p = 0x105a20188,key.class = __NSCFConstantString,key = 不可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1
2019-03-03 12:37:08.098873+0800 MyNewTestDemo[13840:3214742] immutableDic.copy ---key.p = 0x600002398e40,key.class = __NSCFString,key = 可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1
2019-03-03 12:37:08.098950+0800 MyNewTestDemo[13840:3214742] immutableDic.copy ---key.p = 0x600002399260,key.class = __NSCFString,key = 可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.099037+0800 MyNewTestDemo[13840:3214742] immutableDic.copy ---key.p = 0x105a20148,key.class = __NSCFConstantString,key = 不可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.099140+0800 MyNewTestDemo[13840:3214742] immutableDic.copy ---key.p = 0x105a20188,key.class = __NSCFConstantString,key = 不可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1
2019-03-03 12:37:08.160496+0800 MyNewTestDemo[13840:3214742] immutableDic.mutcopy ---key.p = 0x105a20188,key.class = __NSCFConstantString,key = 不可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1
2019-03-03 12:37:08.160610+0800 MyNewTestDemo[13840:3214742] immutableDic.mutcopy ---key.p = 0x600002399260,key.class = __NSCFString,key = 可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.160716+0800 MyNewTestDemo[13840:3214742] immutableDic.mutcopy ---key.p = 0x105a20148,key.class = __NSCFConstantString,key = 不可变对象1 ,obj.p = 0x105a20148,obj.class = __NSCFConstantString,obj = 不可变对象1
2019-03-03 12:37:08.160811+0800 MyNewTestDemo[13840:3214742] immutableDic.mutcopy ---key.p = 0x600002398e40,key.class = __NSCFString,key = 可变对象2 ,obj.p = 0x600002398de0,obj.class = __NSCFString,obj = 可变对象1 */
NSDictionary *immutableDic = @{immutableStrOne:immutableStrOne,immutableStrTwo:mutableStrOne,mutableStrOne:immutableStrOne,mutableStrTwo:mutableStrOne}; NSLog(@"\n immutableDic.p = %p immutableDic.class = %@ \n immutableDic.copy.p = %p immutableDic.copy.class = %@\n immutableDic.mutcopy.p = %p,immutableDic.mutcopy.class= %@",immutableDic,[immutableDic class],[immutableDic copy],[[immutableDic copy] class],[immutableDic mutableCopy],[[immutableDic mutableCopy] class]); [immutableDic enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"immutableDic ---key.p = %p,key.class = %@,key = %@ ,obj.p = %p,obj.class = %@,obj = %@ \n",key,[key class],key,obj,[obj class],obj); }]; [[immutableDic copy] enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"immutableDic.copy ---key.p = %p,key.class = %@,key = %@ ,obj.p = %p,obj.class = %@,obj = %@ \n",key,[key class],key,obj,[obj class],obj);
}]; [[immutableDic mutableCopy] enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"immutableDic.mutcopy ---key.p = %p,key.class = %@,key = %@ ,obj.p = %p,obj.class = %@,obj = %@ \n",key,[key class],key,obj,[obj class],obj); }]; }

容器类对象 针对字典验证

结论:容器类不可变对象  字典和数组的结论是一致的,且对于字典中的key或value ,都是浅拷贝

可以简单整理为:不可变对象的copy,都是浅拷贝,地址相同,
                        可变对象的copy和mutablecopy,都是深拷贝,
                        copy方法返回的是不可变对象,mutableCopy返回的是可变对象,

容器对象内的对象始终是浅拷贝。

代码可点击github,项目内搜索关键字copy and mutableCopy

上一篇:20145205武钰_Exp5 MSF基础应用


下一篇:【转】JSP中的9大隐藏对象