前言
深拷贝和浅拷贝在iOS面试中会经常的出现,作为对OC基础的一种考察,通常的回答就是:深拷贝是对于整个对象的拷贝,而浅拷贝仅仅是对于指针的拷贝。下面,我们就结合场景来聊聊。
非容器类(以字符串为例)
一、不可变对象的拷贝
看如下的代码,打印结果是什么?
NSString *str = @"abc";
NSString *strCopy = [str copy];
NSMutableString *strMCopy = [str mutableCopy];
NSLog(@"str - %@, str_address - %p", str, str);
NSLog(@"strCopy - %@, strCopy_address - %p", strCopy, strCopy);
NSLog(@"strMCopy - %@, strMCopy_address - %p", strMCopy, strMCopy);
打印结果如下:
str - abc, str_address - 0x100001048
strCopy - abc, strCopy_address - 0x100001048
strMCopy - abc, strMCopy_address - 0x1005273c0
结论:
-
copy
和mutableCopy
方法,都会对字符串进行复制操作 - 使用
copy
方法得到的返回值的地址和最初str
的地址是相同的,而使用mutableCopy
方法得到的返回值的地址和最初str
的地址是不同的,这说明针对不可变对象,copy
方法进行了浅拷贝的操作,而mutableCopy
进行了深拷贝操作。
这里还有个问题,查看一下copy
方法和mutableCopy
方法的声明如下:
- (id)copy;
- (id)mutableCopy;
返回值都是id类型。当我们调用这两个方法的时候,应该用什么类型去接收呢?
因为返回的id类型,很显然,我可以使用 NSMutableString
去接收,如下:
NSMutableString *strCopy = [str copy];
[strCopy appendString:@"d"];
NSLog(@"strCopy - %@, strCopy_address - %p", strCopy, strCopy);
打印的结果是什么?
结果是直接崩溃,报错如下:
Attempt to mutate immutable object with appendString:
大概意思是:尝试对不可变的对象进行appendString
修改,而appendString
操作属于可变对象的操作。
虽然使用可变对象接收返回值,但是本质还是返回的是不可变对象。
二、可变对象的拷贝
下面代码打印的结果是什么?
NSMutableString *mStr = [[NSMutableString alloc] initWithString:@"abc"];
NSMutableString *mStrCopy = [mStr copy];
NSMutableString *mStrMCopy = [mStrCopy mutableCopy];
NSLog(@"mStr - %@, mStr_address - %p", mStr, mStr);
NSLog(@"mStrCopy - %@, mStrCopy_address - %p", mStrCopy, mStrCopy);
NSLog(@"mStrMCopy - %@, mStrMCopy_address - %p", mStrMCopy, mStrMCopy);
打印结果:
mStr - abc, mStr_address - 0x1022b4810
mStrCopy - abc, mStrCopy_address - 0xa0cdd0e2447bfe61
mStrMCopy - abc, mStrMCopy_address - 0x1022b4860
结论:
- 对于可变对象,无论使用
copy
方法还是mutableCopy
的方法,都会进行深拷贝
思考:下面的代码打印结果是什么?
NSMutableString *mStrCopy = [mStr copy];
[mStrCopy appendString:@"d"];
以上代码打印结果是什么?
结果是崩溃,报错如下:
-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xb179b2949c0aa1cd'
很明显,就是appendString方法找不到在NSTaggedPointerString类中找不到。
所以,对于可变对象,使用copy
方法,得到的新对象,可以理解为返回的是不可变对象
容器类(以数组为例)
一、不可变对象
示例代码:
NSArray *array = @[@"1", @"2", @"3", @"4"];
NSMutableArray *arrayCopy = [array copy];
NSMutableArray *arrayMCopy = [array mutableCopy];
NSLog(@"array_address - %p", array);
NSLog(@"arrayCopy_address - %p", arrayCopy);
NSLog(@"arrayMCopy_address - %p", arrayMCopy);
NSLog(@"array_address - %p - %p", array[0], array[1]);
NSLog(@"arrayCopy_address - %p - %p", arrayCopy[0], arrayCopy[1]);
NSLog(@"arrayMCopy_address - %p - %p", arrayMCopy[0], arrayMCopy[1]);
打印结果:
array_address - 0x101105ac0
arrayCopy_address - 0x101105ac0
arrayMCopy_address - 0x101105bd0
array_address - 0x100002058 - 0x100002078
arrayCopy_address - 0x100002058 - 0x100002078
arrayMCopy_address - 0x100002058 - 0x100002078
结论:
- 对于不可变对象,使用
copy
方法的地址没有发生改变,证明是浅拷贝,使用mutableCopy
方法后,地址发生了改变,说明是深拷贝。 - 对于数组中的元素,无论使用
copy
和 还是mutableCopy
都不会影响数组中的内容。
二、可变对象
示例代码:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", @"4", nil];
NSMutableArray *mArrayCopy = [mArray copy];
NSMutableArray *mArrayMCopy = [mArray mutableCopy];
NSLog(@"mArray_address - %p", mArray);
NSLog(@"mArrayCopy_address - %p", mArrayCopy);
NSLog(@"mArrayMCopy_address - %p", mArrayMCopy);
NSLog(@"mArray_address - %p - %p", mArray[0], mArray[1]);
NSLog(@"mArrayCopy_address - %p - %p", mArrayCopy[0], mArrayCopy[1]);
NSLog(@"mArrayMCopy_address - %p - %p", mArrayMCopy[0], mArrayMCopy[1]);
打印结果:
mArray_address - 0x1005088b0
mArrayCopy_address - 0x100508b70
mArrayMCopy_address - 0x100508ba0
mArray_address - 0x100001058 - 0x100001078
mArrayCopy_address - 0x100001058 - 0x100001078
mArrayMCopy_address - 0x100001058 - 0x100001078
结论:
与非容器的可变对象的结果类似,无论使用copy
方法还是mutableCopy
方法,都会进行深拷贝。而数组中的内容不受到影响。
以下代码打印什么?
NSMutableArray *mArrayCopy = [mArray copy];
[mArrayCopy addObject:@"5"];
NSLog(@"mArrayCopy_address - %p", mArrayCopy);
结果同样是崩溃,说明尽管是深拷贝,产生了新的对象,使用copy
方法的返回类型,是不可变的。
网友评论