参考了一些文章,感觉写的都不够全面,于是决定自己进行实践并整理,用来作为对相关知识的总结。如有不合理之处,欢迎指正。
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
总结:
调用该方法后,容器内元素地址发生改变,内容也没有随着源数据的变化而变化 所以容器和容器内元素都是深拷贝