• 代码分析Objective-C中的深拷贝与浅拷贝


    oc这门语言属于奇葩中的奇葩,基本类型的对象分为“可变”类型与“不可变”类型。

    比如下面这些类型

    可变不可变
    NSArrayNSMutableArray
    NSStringNSMutableString
    NSNumberNSMutableNumber

    可变类型可以看作是“变量”,不可变类型可以看作是“常量”。当然,只是表面上比较像。

    两种类型都是NSObject的子类,都实现了NSObject中的mutableCopycopy方法。

    有关这两种方法,Apple是这样介绍的:

    在oc中 copy和mutableCopy两个方法是被所有对象(继承自NSObject的类)继承的,这两个方法就是为copy准备的。其中,mutableCopy是为了创建原始对象的可变类型的copy。这两个方法分别调用copyWithZone和mutableCopyWithZone两个方法来进行copy。一个类必须实现copyWithZone或者mutableCopyWithZone,才能进行copy或者mutableCopy。

    两种类型(可变、不可变),两种方法(mutableCopy、copy),就产生了四种组合:

    • 可变类型调用copy
    • 可变类型调用mutableCopy
    • 不可变类型调用copy
    • 不可变类型调用mutableCopy

    这四种组合衍生出了两种概念,浅拷贝深拷贝

    • 浅copy: 指针复制,不会创建一个新的对象。
    • 深copy: 内容复制,会创建一个新的对象。

    概念太空,用代码来理解:

    #import <Foundation/Foundation.h>
    
    int main(int args, const char *argv[]) {
        @autoreleasepool {
            // 可变对象调用copy,mutableCopy
            NSMutableString *mutableString1 = [[NSMutableString alloc] init];
            [mutableString1 setString:@"hello1"];
            id s1 = mutableString1.copy;
            id s2 = mutableString1.mutableCopy;
            NSLog(@"可变对象:%p  %@", mutableString1,mutableString1.class);
            NSLog(@"调用copy:%p  %@", s1, [s1 class]);
            NSLog(@"调用mutableCopy:%p  %@ \n\n", s2, [s2 class]);
            // 可变对象调用copy,mutableCopy
            NSString *immutableString1 = @"hello2";
            id s3 = immutableString1.copy;
            id s4 = immutableString1.mutableCopy;
            NSLog(@"不可变对象:%p  %@", immutableString1,immutableString1.class);
            NSLog(@"调用copy:%p  %@", s3, [s3 class]);
            NSLog(@"调用mutableCopy:%p  %@", s4, [s4 class]);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    以第一部分“可变对象调用copy,mutableCopy”为例

    先创建一个可变对象,然后为其设置一个值“hello1”

    NSMutableString *mutableString1 = [[NSMutableString alloc] init];
    [mutableString1 setString:@"hello1"];
    
    • 1
    • 2

    因为我们不知道copymutableCopy返回的对象具体是什么类型的,因此我们用两个id变量来获取

    id s1 = mutableString1.copy;
    id s2 = mutableString1.mutableCopy;
    
    • 1
    • 2

    %p可以打印出指针的值,[s1 class]可以知道是哪个类,因此可以打印出原变量、copy对象和mutableCopy对象的内存地址与类型,如下。

    NSLog(@"可变对象:%p  %@", mutableString1,mutableString1.class);
    NSLog(@"调用copy:%p  %@", s1, [s1 class]);
    NSLog(@"调用mutableCopy:%p  %@ \n\n", s2, [s2 class]);
    
    • 1
    • 2
    • 3

    打印结果如下(省略无关部分):

    可变对象:0x600003058ba0  __NSCFString
    调用copy:0xaf10ee324c733912  NSTaggedPointerString
    调用mutableCopy:0x600003058bd0  __NSCFString 
    
    • 1
    • 2
    • 3

    可以看出,三个内存地址都是不一样的,说明产生了新的对象,因此

    可变类型调用copy与mutableCopy都是深拷贝

    再看一下不可变部分的代码

    NSString *immutableString1 = @"hello2";
    id s3 = immutableString1.copy;
    id s4 = immutableString1.mutableCopy;
    NSLog(@"不可变对象:%p  %@", immutableString1,immutableString1.class);
    NSLog(@"调用copy:%p  %@", s3, [s3 class]);
    NSLog(@"调用mutableCopy:%p  %@", s4, [s4 class]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    与之前的代码基本类似,直接看输出:

    不可变对象:0x100ce40e8  __NSCFConstantString
    调用copy:0x100ce40e8  __NSCFConstantString
    调用mutableCopy:0x600001980cc0  __NSCFString
    
    • 1
    • 2
    • 3

    可以看出:

    1. 不可变对象调用copy:浅拷贝
    2. 不可变对象调用mutableCopy:深拷贝

    一句话总结:

    只有不可变对象调用copy是浅拷贝,其他都是深拷贝

    有关copy的深度长文:https://www.jianshu.com/p/5f776a4816ee

  • 相关阅读:
    标准lua和luajit的一个代码测试对比
    C语言学习笔记(十二)
    git 配置公钥
    进阶JS-filter用法
    数字孪生产业园开发公司,VR钢铁效果怎么样?强荐广州华锐互动
    2022-08-08-w3d1
    Linux vi编辑器的使用
    MySQL知识【数据库相关概念】第一章
    STM TIM(三) 输入捕获
    【H5写雷达图】使用h5写雷达图等动态图表(两种方式实现)
  • 原文地址:https://blog.csdn.net/qq_15989473/article/details/126016518