iOS 深拷贝和浅拷贝

参考了一些文章,感觉写的都不够全面,于是决定自己进行实践并整理,用来作为对相关知识的总结。如有不合理之处,欢迎指正。

1、非容器型对象(例如 字符串)

属性变量(通过修饰符)

创建model

@interface Fish : NSObject
@property (nonatomic,strong) NSString *strStrong;
@property (nonatomic,copy) NSString *strCopy;

@property (nonatomic,strong) NSMutableString *mutStrStrong;
@property (nonatomic,copy) NSMutableString *mutStrCopy;
@end
//可变字符串进行赋值
  NSMutableString *mutString = [NSMutableString stringWithFormat:@"1234"];

    Fish *f = [[Fish alloc] init];
    f.strStrong = mutString;
    f.strCopy = mutString;
    
    f.mutStrStrong = mutString;
    f.mutStrCopy = mutString;
    
    [mutString appendFormat:@"456"];
    
    NSLog(@"内容:%@-%@-%@",f.strStrong,f.strCopy,mutString);
    NSLog(@"Mut 内容:%@-%@-%@",f.mutStrStrong,f.mutStrCopy,mutString);
    
    NSLog(@"指针:%p-%p-%p",f.strStrong,f.strCopy,mutString);
    NSLog(@"Mut 指针:%p-%p-%p",f.mutStrStrong,f.mutStrCopy,mutString);

打印结果:

内容:1234456-1234-1234456
Mut 内容:1234456-1234-1234456

指针:0x1c4444a40-0xa000000343332314-0x1c4444a40
Mut 指针:0x1c4444a40-0xa000000343332314-0x1c4444a40

//总结:
//strong类型变量,不管是可变还是不可变,用可变字符串进行赋值,都是浅拷贝,指向同一个地址(指针拷贝),所以改变字符内容后,对应的内容也发生变化(copy 或 mutableCopy 则为深拷贝)
//copy类型变量,赋值属于深拷贝,指针地址发生变化(内容拷贝),所以改变字符串内容后,该变量不发生变化(copy 或 mutableCopy  都是深拷贝)


//由于 f.strCopy和 f.mutStrCopy指向同一个地址,
//猜想改变一个变量值另一个也会发生变化,
//于是进行以下操作:

//执行[f.mutStrCopy appendFormat:@"456"]  由于f.mutStrCopy 经过copy赋值后不可变,
//所以调用可变数组方法时就会出现Crash (同理修饰符copy 只能用来修饰不可变类型变量)

//f.mutStrCopy = @“456”直接赋值,则指针地址发生变化(同下不可变字符串赋值)
//所以此两种情况都不会改变copy变量内容
//不可变字符串赋值
    NSString *str = @"123";
    
    Fish *f = [[Fish alloc] init];
    
    f.strStrong = str;
    f.strCopy = str;
    
    f.mutStrStrong = str;
    f.mutStrCopy = str;
    
    str = @"345";
        
    NSLog(@"内容:%@-%@-%@",f.strStrong,f.strCopy,str);
    NSLog(@"Mut 内容:%@-%@-%@",f.mutStrStrong,f.mutStrCopy,str);
    
    NSLog(@"指针:%p-%p-%p",f.strStrong,f.strCopy,str);
    NSLog(@"Mut 指针:%p-%p-%p",f.mutStrStrong,f.mutStrCopy,str);

打印结果

内容:123-123-345
Mut 内容:123-123-345
指针:0x104dbc2a0-0x104dbc2a0-0x104dbc2c0
Mut 指针:0x104dbc2a0-0x104dbc2a0-0x104dbc2c0

总结:
无论是否可变,不可变字符串赋值只是进行浅拷贝(指针拷贝),指向同一个地址
对源字符串进行重新赋值,则会指向新的指针地址,但是属性指针还是原来的地址,所以已经赋值的变量不会发生变化

使用copy时,无论传入的源数据是否可变,复制对象就是一个不可变的
使用strong修饰时,经过赋值后,该变量有可能会受到源数据的影响

2、容器型对象(例数组)

NSMutableArray *mutArr = [NSMutableArray arrayWithObjects:[NSMutableString stringWithFormat:@"1"],@"2",@"3", nil];

NSArray *arr = [mutArr copy];
    NSArray *mcArr = [mutArr mutableCopy]; //返回可变类型
    NSMutableArray *mutArr1 = [mutArr copy]; //返回不可变类型
    NSMutableArray *mutArr2 = [mutArr mutableCopy];
    
    NSMutableString *mutStr = mutArr.firstObject;

    [mutStr appendFormat:@"23"];
    
    
    NSLog(@"数据 : %@-%@-%@-%@-%@",mutArr,arr,mcArr,mutArr1,mutArr2);

    NSLog(@"数据地址 :%p-%p-%p-%p-%p",mutArr,arr,mcArr,mutArr1,mutArr2);    

[arr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSLog(@"arr %p",obj);
    }];
    
    [mcArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSLog(@"mcArr %p",obj);
    }];
    
    [mutArr1 enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSLog(@"mutArr1 %p",obj);
    }];
    
    [mutArr2 enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSLog(@"mutArr2 %p",obj);
    }];
打印结果
数据 : (
    123,
    2,
    3
)-(
    123,
    2,
    3
)-(
    123,
    2,
    3
)-(
    123,
    2,
    3
)-(
    123,
    2,
    3
)
数据地址 :0x1c4454bb0-0x1c4454e80-0x1c4454b80-0x1c4454460-0x1c4454a00

arr 0x1c0452f30 arr 0x10072c3a0 arr 0x10072c3c0
mcArr 0x1c0452f30 mcArr 0x10072c3a0 mcArr 0x10072c3c0
mutArr1 0x1c0452f30 mutArr1 0x10072c3a0 mutArr1 0x10072c3c0
mutArr2 0x1c0452f30 mutArr2 0x10072c3a0 mutArr2 0x10072c3c0

总结:
源数据容器不可变,对不可变变量进行copy操作,只是进行对象的指针copy,该对象指向源容器指针地址,容器是浅拷贝;
源数据是可变类型,则无论被赋值对象是可变还是不可变,进行copy或者mutableCopy,生成不同的容器地址,容器是深拷贝;
容器内元素都指向同一块地址,所以元素1发生改变,容器内元素也发生改变
容器内元素属于浅拷贝(copy后返回的对象是不可变类型的,mutableCopy后返回的对象是可变类型)
//- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;

NSArray *items_copy = [[NSArray alloc] initWithArray:mutArr copyItems:YES];
NSMutableArray *mutitems_copy = [[NSMutableArray alloc] initWithArray:mutArr copyItems:YES];
调用该方法后,再次进行以上操作,打印结果:

数据 :...(
    1,
    2,
    3
)-(
    1,
    2,
    3
)

数据地址 :0x1c0440510-0x1c0440510-0x1c025f7d0-0x1c0440510-0x1c0440660-0x1c0444fe0-0x1c04405a0

mutArr2 0x1c0443bd0 mutArr2 0x1040c8420 mutArr2 0x1040c8440 mutArr2 0x1040c84a0
items_copy 0xa000000000000311 items_copy 0x1040c8420 items_copy 0x1040c8440
mutitems_copy 0xa000000000000311 mutitems_copy 0x1040c8420 mutitems_copy 0x1040c8440

总结:
调用该方法后,容器内元素地址发生改变,内容也没有随着源数据的变化而变化  所以容器和容器内元素都是深拷贝
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 在iOS开发中深拷贝和浅拷贝是一个被大家说烂的话题了,但是今天还是要拿出来说一说。原因是,前段时间在微信朋友圈看到...
    WSJay阅读 4,444评论 1 8
  • 在工作中,有时会涉及到深拷贝和浅拷贝的内容,发现有些地方理解的不够透彻,所以在网上搜集资料总结一下,主要分四个方面...
    LeverTsui阅读 8,908评论 3 5
  • 浅拷贝就是拷贝后,并没有进行真正的复制,拷贝后的对象和原对象都指向同一块内存地址 深拷贝是真正的复制了一份,复制的...
    最是光阴化浮末阅读 3,339评论 1 1
  • 清风晓月茗茶 骤雨急云落花 策马风沙天下 柔情几度年华
    月影山人阅读 2,981评论 0 0
  • Ashley彭 20180104 ❤️4组 彭钰博 学龄前 #从自己做起,给闺女树立榜样# 孩子第一个30天目标:...
    Ashley彭阅读 1,414评论 0 0

友情链接更多精彩内容