美文网首页初见
OC基础之深拷贝和浅拷贝

OC基础之深拷贝和浅拷贝

作者: LazyLoad | 来源:发表于2020-03-12 19:45 被阅读0次

    前言

    深拷贝和浅拷贝在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
    

    结论:

    • copymutableCopy方法,都会对字符串进行复制操作
    • 使用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方法的返回类型,是不可变的。

    相关文章

      网友评论

        本文标题:OC基础之深拷贝和浅拷贝

        本文链接:https://www.haomeiwen.com/subject/rpzijhtx.html