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]);
    }

    执行结果:

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

  • 相关阅读:
    [禅悟人生]如春风般吹开他人冬眠的良心
    [禅悟人生]先学做人, 再学做佛
    [禅悟人生]悟得自性则天地开阔
    [禅悟人生]"执著"是自缚的茧
    [禅悟人生]时常自省, 扫却心中尘埃
    [禅悟人生]心不动才能真正认清自己
    [禅悟人生]自卑裹足不前, 就无法成就自己
    [禅悟人生]有自知之明, 在深浅之间权衡做人
    禅悟人生目录
    [禅悟人生]认识自己才能了解外部世界
  • 原文地址:https://www.cnblogs.com/acBool/p/5146639.html
Copyright © 2011-2022 走看看