初见

OC基础之深拷贝和浅拷贝

2020-03-12  本文已影响0人  LazyLoad

前言

深拷贝和浅拷贝在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方法的声明如下:

- (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

结论:

思考:下面的代码打印结果是什么?

        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

结论:

二、可变对象

示例代码:

        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方法的返回类型,是不可变的。

上一篇下一篇

猜你喜欢

热点阅读