iOS 浅拷贝 深拷贝

概念


  • 浅拷贝:指针拷贝,复制一个新的指针,指向同一块内存区域。即复制的对象和原对象都指向同一个内存


    浅拷贝
  • 深拷贝:内容拷贝,拷贝数据到一块新内存区域,指针指向新拷贝的内存。


    深拷贝.png
  • 非容器不可变对象/可变对象:NSString/ NSMutableString等

  • 容器不可变对象/可变对象:NSArray/NSMutableArray等

先说说Strong修饰的变量


@interface Copy()
@property (nonatomic,strong)NSMutableString *strongStringA;
@property (nonatomic,strong)NSMutableString *strongStringB;

@end

@implementation Copy

-(void)strongStringCopy{
    NSMutableString *string = [NSMutableString stringWithFormat:@"name"];
    NSLog(@"原始NSMutableString的地址:%p",string);
    self.strongStringA=string;
    NSLog(@"对strongStringA赋值后的地址:%p",self.strongStringA);
    [string appendString:@" is kindom_0129"];
    NSLog(@"原始值修改后的地址:%p 值:%@",string,string);
    NSLog(@"对原始值修改后strongStringA的地址:%p 值:%@",self.strongStringA,self.strongStringA);
}


@end

打印结果:

原始NSMutableString的地址:0x6000018a57d0
对strongStringA赋值后的地址:0x6000018a57d0
原始值修改后的地址:0x6000018a57d0 值:name is kindom_0129
对原始值修改后strongStringA的地址:0x6000018a57d0 值:name is kindom_0129

  • 结论:
    A使用属性对可变字符串做出了appendstring这样的操作,B中的值也会发生修改。
    strong: 为浅拷贝,也就是指针引用

非容器不可变对象NSString


    NSString *string = [NSString stringWithFormat:@"name"];
    NSLog(@"原始string的地址:%p",string);
    NSString *copyString = [string copy];
    NSLog(@"拷贝string的地址:%p",copyString);
    NSMutableString *copyStringB = [string mutableCopy];
    NSLog(@"深拷贝string的地址:%p",copyStringB);
    [copyStringB appendString:@"id kindom_0129"];
    NSLog(@"深拷贝string的值:%@",copyStringB);

打印结果:
原始string的地址:0xe44d9dca7936d694
拷贝string的地址:0xe44d9dca7936d694
深拷贝string的地址:0x600003ed1260
深拷贝string的值:nameid kindom_0129

可以看出copy时对象的地址与原来的相同,而mutableCopy地址改变了,并且能够对其进行修改

结论:
1.对于非容器不可变对象的copy为浅拷贝,mutableCopy为深拷贝
2.浅拷贝获得的对象地址和原对象地址一致, 返回的对象为不可变对象
3.深拷贝返回新的内存地址,返回对象为可变对象

非容器可变对象NSMutableString


首先看下面这段代码:

-(void)copyString{
    NSMutableString *string = [NSMutableString stringWithFormat:@"name"];
    NSLog(@"原始string的地址:%p",string);
    
    NSMutableString *copyString = [string copy];
    NSLog(@"拷贝string的地址:%p",copyString);
    
    [copyString appendString:@"test"];
}

结果呢?


屏幕快照 2019-08-29 14.23.25.png

看到了吗?居然crash了,为什么呢。我们细看下:
我们的MutableString对象调用了copy之后,拷贝出来的字符串内存地址发生了变化,也就是说这里是发生了深拷贝。
接着我们使用copyString调用appendString方法发生了很常规的闪退,日志显示我们拷贝出来的是NSTaggedPointerString,这是个不可变字符串。

也就是说可变字符串在copy之后会发生深拷贝,拷贝出来的是一个不可变字符串!

再来看看下面这段代码:

 -(void)copyString{
    NSMutableString *string = [NSMutableString stringWithFormat:@"name"];
    NSLog(@"原始string的地址:%p",string);

    NSMutableString *copyString = [string copy];
    NSLog(@"拷贝string的地址:%p",copyString);
    
    NSMutableString *copyStringB = [string mutableCopy];
    NSLog(@"深拷贝string的地址:%p",copyStringB);
    [copyStringB appendString:@"id kindom_0129"];
    NSLog(@"深拷贝string的值:%@",copyStringB);
}

结果:
原始string的地址:0x60000140f9f0
拷贝string的地址:0xd62b10f4fd1f50c5
深拷贝string的地址:0x60000147a310
深拷贝string的值:nameid kindom_0129

结论:
1.对于非容器可变对象的copy为深拷贝
2.mutableCopy为深拷贝,并且可以修改
3.可变字符串在copy之后会发生深拷贝,拷贝出来的是一个不可变字符串!

容器不可变对象:NSArray等


先来看看下面的代码:

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
    
    NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
    NSArray *copyArray = [array copy];
    NSArray *mutableCopyArray = [array mutableCopy];
    
    NSLog(@"array_p: %p, class: %@", array, [array class]);
    NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
    NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
    
    NSLog(@"======原对象=====");
    NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
    NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
    
    NSLog(@"======copy对象=====");
    NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
    NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
    
    NSLog(@"======mutableCopy对象=====");
    NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
    NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);

结果:
array_p: 0x6000005cca80, class: __NSArrayI
copyArray_p: 0x6000005cca80, class: __NSArrayI
mutableCopyArray_p: 0x600000bd03c0, class: __NSArrayM
======原对象=====
object_p: 0x600000bd00c0, class: __NSCFString
object_p: 0x10b5211e0, class: __NSCFConstantString
======copy对象=====
object_p: 0x600000bd00c0, class: __NSCFString
object_p: 0x10b5211e0, class: __NSCFConstantString
======mutableCopy对象=====
object_p: 0x600000bd00c0, class: __NSCFString
object_p: 0x10b5211e0, class: __NSCFConstantString

结论:
1.copy为浅拷贝;
2.mutableCopy为深拷贝;
3.无论是浅拷贝还是深拷贝,容器内的元素仍然是浅拷贝。

容器可变对象:NSMutableArray等


代码:

   NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
    
    NSMutableArray *array = [NSMutableArray arrayWithObjects:str1, @"非容器不可变对象", nil];
    NSMutableArray *copyArray = [array copy];
    NSMutableArray *mutableCopyArray = [array mutableCopy];
    
    NSLog(@"array_p: %p, class: %@", array, [array class]);
    NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
    NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
    
    NSLog(@"======原对象=====");
    NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
    NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
    
    NSLog(@"======copy对象=====");
    NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
    NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
    
    NSLog(@"======mutableCopy对象=====");
    NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
    NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);

结果:
array_p: 0x6000029f1c50, class: __NSArrayM
copyArray_p: 0x6000027aab80, class: __NSArrayI
mutableCopyArray_p: 0x6000029f19b0, class: __NSArrayM
======原对象=====
object_p: 0x6000029f1b00, class: __NSCFString
object_p: 0x10bdb11e0, class: __NSCFConstantString
======copy对象=====
object_p: 0x6000029f1b00, class: __NSCFString
object_p: 0x10bdb11e0, class: __NSCFConstantString
======mutableCopy对象=====
object_p: 0x6000029f1b00, class: __NSCFString
object_p: 0x10bdb11e0, class: __NSCFConstantString

我们再添加一行代码:

[copyArray addObject:@"dddd"];

此时运行发现crash了:


image.png

结论:
1.容器类可变对象mutableCopy和copy都返回一个新的容器,
2.容器内的元素仍然是浅拷贝
3.容器类可变对象copy后生成的新对象为不可变对象,这与非容器类可变对象copy后是一样的

***总结:


1.copy并不一定是浅拷贝,如果被拷贝的对象是可变数组或者字符串,这时候会发生深拷贝,反之则是浅拷贝。
2.copy出来的一定是不可变对象
3.对于容器对象,无论是浅拷贝还是深拷贝,容器内的内容都是浅拷贝
4.对于可变对象的深拷贝mutableCopy可以修改

你可能感兴趣的:(iOS 浅拷贝 深拷贝)