zoukankan      html  css  js  c++  java
  • iOS中的深复制与浅复制

    很多语言中都有深复制浅复制的概念,如C++,ObjC等。简单来说,浅复制就是两个变量指向了同一块内存区域,深复制就是两个变量指向了不同的内存区域,但是两个内存区域里面的内容是一样的。

    浅复制示意图:

    深复制示意图:

    iOS开发中,浅复制和深复制要更复杂一些,涉及到集合对象和非集合对象的copy与mutableCopy。

    非集合对象:如NSString,NSInteger,NSNumber……

    集合对象:如NSArray,NSDictionary,……

    1:非集合对象的copy与mutableCopy。

    非集合对象的copy与mutableCopy,只需要遵循以下规则即可:

      (1)可变对象的copy和mutableCopy方法都是深复制

      (2)不可变对象的copy方法是浅复制,mutableCopy方法是深复制

      (3)copy方法返回的对象是不可变对象

    下面通过代码来验证:

    可变对象的copy与 mutableCopy方法:

    void testMutable()
    {
        //可变对象的复制,copy和mutableCopy都是深拷贝
        NSMutableString *str1 = [NSMutableString stringWithString:@"test"];
        NSMutableString *str2 = [str1 copy];
        //copy返回的是不可变对象,因此str2不能改变,会发生崩溃
        //[str2 appendString:@"test"];
        NSMutableString *str3 = [str1 mutableCopy];
        [str3 appendString:@"test"];
        NSLog(@"%@ %@ %@",str1,str2,str3);
        NSLog(@"%p %p %p",str1,str2,str3);
    }

    执行结果:

    可以看到,三个字符串的地址是不相同的,说明copy和 mutableCopy方法都是深复制。

    不可变对象的copy与mutableCopy方法:

    void testNoMutable()
    {
        NSString *str1 = @"test";
        //直接copy是浅复制
        NSMutableString *str2 = [str1 copy];
        //copy返回的是不可变对象,str2不能被修改,因此会发生崩溃
        //[str2 appendString:@"test"];
        //mutableCopy是深复制
        NSMutableString *str3 = [str1 mutableCopy];
        [str3 appendString:@"test"];
        NSLog(@"%@ %@ %@",str1,str2,str3);
        NSLog(@"%p %p %p",str1,str2,str3);
    }

    执行结果:

    可以看到:前两个地址一样,第三个地址不一样,因此不可变对象的copy方法是浅复制,mutableCopy方法是深复制。

    另外需要注意:无论是可变对象还是不可变对象,copy 方法返回的对象都是不可变的。

    2:集合对象的copy与mutableCopy

    实际上,集合对象与非集合对象所遵循的规则基本上是一样的。

    可变对象的的copy与mutableCopy 方法

    验证代码:

    void testSetMutable()
    {
        NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
        //可变对象copy是深复制
        NSMutableArray *array2 = [array1 copy];
        //copy返回的是不可变对象,array2不能被修改,因此会崩溃
        //[array2 addObject:@"d"];
        //可变对象的mutableCopy是深复制
        NSMutableArray *array3 = [array1 mutableCopy];
        [array3 addObject:@"d"];
        NSLog(@"%p %p %p",array1,array2,array3);
    }

    执行结果:

    可以看到地址是不一样的。说明可变对象的copy和mutableCopy方法都是深复制。

    不可变对象的copy与mutableCopy方法

    验证代码:

    void testSetNoMutable()
    {
        NSArray *array1 = @[@"a",@"b",@"c"];
        //不可变对象的copy方法,浅复制
        NSArray *array2 = [array1 copy];
        //不可变对象的mutableCopy方法,深复制
        NSArray *array3 = [array1 mutableCopy];
        NSLog(@"%p %p %p",array1,array2,array3);
    }

    执行结果:

    可以看到,前两个地址一样,第三个地址不一样。说明不可变对象的copy方法是浅复制,mutableCopy方法是深复制。

    集合对象和非集合对象的一个差别:

    上面说的集合对象的深复制并不是严格意义上的深复制,而是单层深复制。

    单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。比如说

    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];

    调用copy方法   NSArray *array2 = [array1 copy] ,有分配了一块内存,array2指向了这块内存,但是数组内部的元素,指向的仍然是数组1内部的元素,即内部元素是浅复制。

    验证代码:

    void testSetMutable()
    {
        NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
        //可变对象copy是深复制
        NSMutableArray *array2 = [array1 copy];
        //copy返回的是不可变对象,array2不能被修改,因此会崩溃
        //[array2 addObject:@"d"];
        //可变对象的mutableCopy是深复制
        NSMutableArray *array3 = [array1 mutableCopy];
        [array3 addObject:@"d"];
        NSLog(@"%p %p %p",array1,array2,array3);
        NSLog(@"%p %p %p",array1[0],array2[0],array3[0]);
    }

    执行结果:

    可以看到,三个数组的第一个元素的地址是一样的,也就是说内部元素是浅复制。

    3:集合对象的完全复制

    集合对象的完全复制,就是集合中的每一层的元素都是深复制。

    方法一:

    使用 initWith***: copyItems:YES  方法。

    代码:

    void testFullCopy()
    {
        NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
        NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
        NSLog(@"%p %p",array1,array2);
        NSLog(@"%p %p",array1[0],array2[0]);
    }

    执行结果:

    可以看到数组元素的地址不一样。

    方法二:

    先将集合进行归档,然后再解档。代码如下:

    void testFullCopy2()
    {
        NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
        NSArray *array2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1 ] error:nil];
        NSLog(@"%p %p",array1,array2);
        NSLog(@"%p %p",array1[0],array2[0]);
    }

    执行结果:

    可以看到数组元素的地址不一样。

  • 相关阅读:
    为什么要配置PATH环境变量?如何配置
    JDK,JRE,JVM三者之间的关系,以及JDK、JRE包含的主要结构有哪些
    常用的开发工具
    API文档说明
    Java注释(Comment)
    EditPlus和notepad++配置
    Java第一个程序--HelloWorld
    cmd命令和快捷键
    如何以计算机的方式去思考
    藤野先生后来怎么样了?被自卑隔阂的友谊
  • 原文地址:https://www.cnblogs.com/acBool/p/5146639.html
Copyright © 2011-2022 走看看