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 *)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 总结: 调用该方法后,容器内元素地址发生改变,内容也没有随着源数据的变化而变化 所以容器和容器内元素都是深拷贝 ```

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