美文网首页
深浅拷贝

深浅拷贝

作者: 那样风采 | 来源:发表于2019-09-26 20:44 被阅读0次

实例化的对象存储在堆区,而指向对象的指针一般存储在栈区。实际上拷贝分为深拷贝(one level deep copy),浅拷贝(shallow copy)和完全拷贝(real deep copy)三种。

  • 浅拷贝:在操作中,对于被复制对象的每一层都是指针复制。


  • 深拷贝:在操作中,对于被复制对象,至少有一层是深复制。


  • 完全拷贝:在操作中,对于被复制对象,每一层都是对象复制。
image.png

注意

1、深拷贝和完全拷贝

深拷贝,就是把原有对象内容直接克隆一份新的对象,但是这里有一个坑,就是深拷贝只是复制一层对象,而不是复制第二层或者更深层的对象,例如:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM1 = [NSMutableString stringWithString:@"1"];
    NSMutableString *strM2 = [NSMutableString stringWithString:@"2"];
    NSMutableArray *arrM1 = [NSMutableArray arrayWithObjects: strM1, strM2, nil];

   // 深拷贝原数组
    NSMutableArray *arrM2 = [arrM1 mutableCopy];

   // 深拷贝之后,再修改字符“1“ 为 ”11“
    NSMutableString *strM3 = [arrM1 objectAtIndex:0];
    [strM3 appendString:@"1"];

    NSLog(@"strM1--%@",arrM1);
    NSLog(@"strM2--%@",arrM2);
}

看结果:

// 原数组
2017-03-14 00:22:02.260 [5522:393850] strM1--(
    11,
    2
)
// 深拷贝数组
2017-03-14 00:22:02.261 [5522:393850] strM2--(
    11,
    2
)

结论:为什么深拷贝已经复制了对象,那么原对象为什么也同步变化?这里就是深拷贝和完全拷贝的原因,深拷贝只是拷贝了一层数组,但是里面的字符串没有拷贝,两个数组都是用的同一个地址的字符串,所以改变一个,原对象也发生了变化。可以做下面这样的修改。

// copyIitems为YES
NSMutableArray *arrM2 = [[NSMutableArray alloc] initWithArray: arrM1 copyItems:YES];

查看结果

2017-03-14 00:45:45.389 [5916:425450] arrM1--(
    11,
    2
)
2017-03-14 00:45:45.390 [5916:425450] arrM2--(
    1,
    2
)

可以利用这个方法,得到的是多一层的深复制,里面的字符串地址也进行了复制,所以改变strM3的值,不影响arrM1的值。你认为这样就解决了吗?再看下面的问题。

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM1 = [NSMutableString stringWithString:@"1"];
    NSMutableString *strM2 = [NSMutableString stringWithString:@"2"];
    NSMutableArray *arrM1 = [NSMutableArray arrayWithObjects: strM1, strM2, nil];

    // 嵌套了一层数组,arrM1
    NSMutableArray *arrM2 = [NSMutableArray arrayWithObjects: strM1, strM2, arrM1, nil];

    // copyItems会多拷贝一层
    NSMutableArray *arrM3 = [[NSMutableArray alloc] initWithArray:arrM2 copyItems:YES];
     
    // 两层深拷贝后再修改字符串
    NSMutableString *strM3 = [arrM1 objectAtIndex:0];
    [strM3 appendString:@"1"];

    NSLog(@"arrM2--%@",arrM2);
    NSLog(@"arrM3--%@",arrM3);
}

查看结果

2017-03-14 00:55:57.604 [6080:438490] arrM2--(
    11,
    2,
        (
        11,
        2
    )
)
2017-03-14 00:55:57.606 [6080:438490] arrM3--(
   // 第二层没有变化
    1,
    2,
        (
        // 第三层的字符串同步变化了。因为copyItem只是多拷贝了一层
        11,
        2
    )
)

结论:可以发现外层的深复制了,原对象和拷贝后的对象不是同一地址,再往里看一层都变化了,就没有深复制,也就是说再增加一层NSMutableArray *arrM2 = [[NSMutableArray alloc] initWithArray:arrM1 copyItems:YES];这个方法管不了那么多层数。可以采用归档和解档解决该问题:

NSMutableArray *arrM3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arrM2]];

查看结果

2017-03-14 01:17:23.204 [6396:464958] arrM2--(
    11,
    2,
        (
        11,
        2
    )
)
2017-03-14 01:17:23.204 [6396:464958] arrM3--(
    1,
    2,
        (
        1,
        2
    )
)

结论:可以看到实现了完全复制,就没有层数的限制


2、NSString的copy和strong

NSString被copy和strong修饰会有什么不同:

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,copy) NSString *str;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableString *strM = [[NSMutableString alloc] initWithString:@"bestDay"];
    self.str = strM;
    [strM appendString:@"OfThisYear"];
    NSLog(@"str----%@---%p",self.str,self.str);
    NSLog(@"strM----%@---%p",strM,strM);

}
@end

直接查看结果

2017-03-14 08:53:01.874 [789:18128] str----bestDay---0xa796144747365627
2017-03-14 08:53:01.875 [789:18128] strM----bestDayOfThisYear---0x600000071280

结论:可以看到copy修饰的str,在赋值以后,可变字符串strM发生了变化并不会影响str的值。从打印结果来看是因为二者不是一个地址,所以不会相互影响。为什么?
是因为copy修饰的属性setter方法,先release旧值,copy新值再赋值给成员变量,不可变copy是深拷贝,就是内容拷贝,地址变化了
接着看strong修饰的情况:

@property (nonatomic,strong) NSString *str;

直接查看结果

2017-03-14 09:03:36.756 [968:29890] str----bestDayOfThisYear---0x6000002600c0
2017-03-14 09:03:36.757 [968:29890] strM----bestDayOfThisYear---0x6000002600c0

结论:被strong修饰以后只是强指针引用,并未改变地址,所以str的值会随着strM进行变化,二者的地址也是相同的。


3、理解copy和retain的不同

在MRC下进行测试,先看代码

//copy和retain的区别
- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableArray *arrM = [NSMutableArray arrayWithObjects:@"111",@"222",@"333", nil];

    NSMutableArray *arrMRetain = [arrM retain];
    NSMutableArray *arrMCopy = [arrM copy];
    [arrM removeLastObject];

    NSLog(@"arrMRetain--%@--%p--%lu",arrMRetain,arrMRetain,[arrMRetain retainCount]);
    NSLog(@"arrMCopy--%@--%p--%lu",arrMCopy,arrMCopy,[arrMCopy retainCount]);

}

查看结

2017-03-14 20:16:59.895 copy和retain的区别[2816:177901] arrMRetain--(
    111,
    222
)--0x60000005cf50--2
2017-03-14 20:16:59.895 [2816:177901] arrMCopy--(
    111,
    222,
    333
)--0x60000005cf80--1

结论:copy是深复制,retainCount为1,retain是浅复制,retain是使原来对象引用计数加1,所以arrM和arrMRetain是同一地址,所以remove最后一个元素,arrMRetain也跟着变化了。

参考

ios中的拷贝你知道多少?

相关文章

  • 2018-08-29

    深浅拷贝 1.根据拷贝内容的不同,分为深浅拷贝 深拷贝:内容...

  • js的深浅拷贝

    js的深浅拷贝可以分为数组的深浅拷贝和对象的深浅拷贝 一、数组的深浅拷贝如果只是简单的将数组中的元素付给另外一个数...

  • Python—浅拷贝与深拷贝

    浅拷贝 深拷贝 深浅拷贝的作用

  • 深浅拷贝

    先来了解一下这些:在js中变量类型基本分为两种:基本数据类型和引用数据类型;基本类型:Underfied Null...

  • 深浅拷贝

    浅拷贝是对一个对象的顶层拷贝。通俗的理解就是:拷贝了引用,并没有拷贝内容。 深拷贝是对于一个对象所有层次的拷贝(递...

  • 深浅拷贝

    深浅拷贝.copy 浅拷贝 这是一个方法,浅拷贝修改可变类型是会将原数据也一块修改 Copy.deepcopy 深...

  • 深浅拷贝

    1:is 和 ==的区别 is 是比较两个引用是否指向了同一个对象(地址引用比较)。== 是比较两个对象是否相等。...

  • 深浅拷贝

    函数的传递,与matlab不同,具有以下特点: 1.直接赋值会带来不同ID,例如,a=2,b=2 2.传递引用赋值...

  • 深浅拷贝

    最近一直被问到深浅拷贝的问题。自己也确实不太清楚怎么回事,现在来研究一下。 什么是深浅拷贝 浅拷贝:指针拷贝,不会...

  • 深浅拷贝

    概念: 浅复制:不拷贝对象本身,仅仅是拷贝指向对象的指针深复制:是直接拷贝整个对象内存到另一块内存中 注意:这里有...

网友评论

      本文标题:深浅拷贝

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