iOS深拷贝、浅拷贝、copy、mutableCopy的理解

110 阅读5分钟

不要混淆认为浅拷贝 = copy,深拷贝 = mutableCopy

先说一下深拷贝、浅拷贝、copy、mutableCopy的概念。

深拷贝浅拷贝

  • 浅拷贝(Shallow Copy) :浅拷贝是指复制对象时,只复制对象的结构和引用,不复制对象中的数据。也就是说,拷贝后的对象和原对象指向同一个内存地址。如果原对象中的元素是可变的,那么修改原对象会影响到拷贝后的对象。
  • 深拷贝(Deep Copy) :深拷贝是指复制对象时,除了复制对象的结构外,还会复制对象中的所有数据。即拷贝后的对象和原对象的数据是完全独立的,会产生新的内存地址。修改原对象不会影响到拷贝后的对象。

copymutableCopy

  • copy:返回一个不可变的拷贝。对于不可变对象(如 NSString),copy 会直接返回自己,不会产生新的内存地址,因为它本身已经是不可变的;对于可变对象(如 NSMutableArray),copy 会返回不可变的拷贝,即不可变的对象,有新的内存地址。
  • mutableCopy:返回一个可变的拷贝。如果原始对象是不可变的,mutableCopy 会创建一个新的可变对象,和原对象指向不同的内存地址;如果原始对象是可变的,mutableCopy 会创建一个新的可变对象,和原对象指向不同的内存地址。

接下来就是代码验证,附带了打印日志。

NSString *oldModel = @"测试String";
NSString *oldModel2 = [oldModel copy];
NSString *oldModel2_1 = [oldModel mutableCopy];
NSString *oldModel3_1 = oldModel;
NSLog(@"old ---XfPayReportModel NSString %@  ---%p ---- %@  ---%p---- %@  ---%p--- %@  ---%p",oldModel,oldModel,oldModel2,oldModel2,oldModel2_1,oldModel2_1,oldModel3_1,oldModel3_1);

//打印结果:
old ---XfPayReportModel NSString 测试String  ---0x105833ef0 ---- 测试String  ---0x105833ef0---- 测试String  ---0x303f59a40--- 测试String  ---0x105833ef0

oldModel = @"adasdaddsasddas";
NSLog(@"old ---XfPayReportModel NSString %@  %@   %@",oldModel,oldModel2,oldModel3_1);

//打印结果:
old ---XfPayReportModel NSString adasdaddsasddas  测试String   测试String

总结:
String类型copy不会有新的内存地址,只是copy了一个新的指针变量,但是由于String不可变,所以无法去改变原本对象的值,当重新赋值是,是将原本对象的指针指向了新的变量内存地址。mutableCopy会开辟新的内存地址,形成行的对象。
此时的copy是浅拷贝,mutableCopy是深拷贝

         

NSMutableString *oldModel4 = [NSMutableString stringWithString:@"qweqweweqw"];
NSMutableString *oldModel5= oldModel4.mutableCopy;
NSMutableString *oldModel6 =  oldModel4.copy;
NSMutableString *oldModel7 =  oldModel4;
NSLog(@"old ---XfPayReportModel NSMutableString %@  ---%p ---- %@  ---%p---- %@  ---%p",oldModel4,oldModel4,oldModel5,oldModel5,oldModel6,oldModel6);

//打印结果:
old ---XfPayReportModel NSMutableString qweqweweqw  ---0x303f59680 ---- qweqweweqw  ---0x303f599b0---- qweqweweqw  ---0x303083e00

[oldModel4 appendString:@" World"];
NSLog(@"old ---XfPayReportModel NSMutableString %@  %@   %@",oldModel4,oldModel5,oldModel6,oldModel7);

//打印结果:
old ---XfPayReportModel NSMutableString qweqweweqw World  qweqweweqw   qweqweweqw  qweqweweqw World

总结:
执行copy时,产生新的内存地址。原本可变String变为不可变String。无法继续使用可变String的API,因为继续使用会报错。比如appending函数。
执行mutableCopy时也会产生新的内存地址。仍然为可变String类型。
当对原可变String执行appending函数改变值的时候,执行copy和mubalrCopy产生的新对象都不会受到影响。只有直接赋值的oldModel7会受到影响,变为最新值。

            

NSDictionary *dict = @{@"aaaa1111":@"bbbbbb11111"};
NSDictionary *dict0 = dict;
NSDictionary *dict1 = [dict copy];
NSDictionary *dict2 = [dict mutableCopy];
NSLog(@"old ---XfPayReportModel NSDictionary---%p ---%p ---%p ---%p---%@ ---%@ ---%@ ---%@", dict, dict0, dict1, dict2, dict, dict0, dict1, dict2);

//打印结果:
old ---XfPayReportModel NSDictionary---0x303083b60 ---0x303083b60 ---0x303083b60 ---0x303091ae0---{
    aaaa1111 = bbbbbb11111;

} ---{

    aaaa1111 = bbbbbb11111;

} ---{

    aaaa1111 = bbbbbb11111;

} ---{

    aaaa1111 = bbbbbb11111;

}
  
  总结:如String
NSMutableDictionary *payReportsMap = [NSMutableDictionary dictionary];
[payReportsMap setValue:[NSMutableString stringWithString:@"aaaa"] forKey:[NSMutableString stringWithString:@"bbbb"]];
NSMutableDictionary<NSMutableString *, NSMutableString *> *tempMap = payReportsMap;
NSMutableDictionary<NSMutableString *, NSMutableString *> *tempMap1 = [payReportsMap copy];
NSMutableDictionary<NSMutableString *, NSMutableString *> *tempMap2 = [payReportsMap mutableCopy];
NSLog(@"old ---XfPayReportModel NSMutableDictionary---%p ---%p ---%p ---%p---%@ ---%@ ---%@ ---%@", payReportsMap, tempMap, tempMap1, tempMap2, payReportsMap, tempMap, tempMap1, tempMap2);

//打印结果:
old ---XfPayReportModel NSMutableDictionary---0x303092940 ---0x303092940 ---0x3030d9f00 ---0x3030c78c0---{

    bbbb = aaaa;

} ---{

    bbbb = aaaa;

} ---{

    bbbb = aaaa;

} ---{

    bbbb = aaaa;

}

[payReportsMap setValue:[NSMutableString stringWithString:@"aaaa1111"] forKey:[NSMutableString stringWithString:@"ddddd"]];
NSLog(@"old ---XfPayReportModel NSMutableDictionary---%p ---%p ---%p ---%p---%@ ---%@ ---%@ ---%@", payReportsMap, tempMap, tempMap1, tempMap2, payReportsMap, tempMap, tempMap1, tempMap2);

//打印结果:
   old ---XfPayReportModel NSMutableDictionary---0x303092940 ---0x303092940 ---0x3030d9f00 ---0x3030c78c0---{

    bbbb = aaaa;

    ddddd = aaaa1111;

} ---{

    bbbb = aaaa;

    ddddd = aaaa1111;

} ---{

    bbbb = aaaa;

} ---{

    bbbb = aaaa;

} 

总结:如MutableString
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"1",@"2"]];
NSMutableArray *array1 = array;
NSMutableArray *array2 = [array copy];
NSMutableArray *array3 = [array mutableCopy];
NSLog(@"old ---XfPayReportModel NSMutableArray ---%p ---%p ---%p ---%p---%@ ---%@ ---%@ ---%@", array, array1, array2, array3, array, array1, array2, array3);

//打印结果:
old ---XfPayReportModel NSMutableArray ---0x303ebde30 ---0x303ebde30 ---0x3030c9c80 ---0x303ebe6a0---(

    1,

    2

) ---(

    1,

    2

) ---(

    1,

    2

) ---(

    1,

    2

)


[array addObject:@"3"];
[array addObjectsFromArray:@[@"4",@"5"]];
NSLog(@"old ---XfPayReportModel NSMutableArray ---%p ---%p ---%p ---%p---%@ ---%@ ---%@ ---%@", array, array1, array2, array3, array, array1, array2, array3);

//打印结果:
old ---XfPayReportModel NSMutableArray ---0x303ebde30 ---0x303ebde30 ---0x3030c9c80 ---0x303ebe6a0---(

    1,

    2,

    3,

    4,

    5

) ---(

    1,

    2,

    3,

    4,

    5

) ---(

    1,

    2

) ---(

    1,

    2

)

总结:如MutableString
写在最后:
1.当需要对一个数组,字典操作时,如果是一个共用数组字典,请先copy或者mutableCopy之后再操作,避免多方操作同个字典导致的越界等崩溃。
2.直接的赋值操作=是赋值的变量指针,指向的还是同一块内存地址,所以当原本的对象值发生改变时,会影响到新的对象。所以在复制新的对象后不想再改变的时候,请赋值时使用copy or mutableCopy。