IOS详解深拷贝和浅拷贝的概念、具体的使用以及对于容器类(NSArray,NSDictionary 等)和非容器类(NSString,NSdata 等)拷贝的差异
来源:互联网 发布:佳能网络打印机设置ip 编辑:程序博客网 时间:2024/06/04 19:14
本文首先先从介绍深拷贝和浅拷贝的概念问题开始,以便更好的理解和学习他们的使用环境.
使用深拷贝和浅拷贝的前提就是使用对象必须遵循NSCopying 或者 NSMutableCopying 协议,以下为截取自 NSArray 的头文件声明
浅拷贝的概念:浅拷贝就是对当前对象指针的拷贝;
深拷贝的概念:深拷贝是对当前对象的拷贝;
举个例子就是浅拷贝就是给当前对象拷贝了一个影子,当被拷贝对象值改变时,新拷贝出来的对象(影子)指向该对象,所以也会使你拷贝出来的对象改变值;
深拷贝就相当于给当前对象克隆了一个一模一样的对象,新拷贝出来的对象指针和内存地址都发生了变化,和原来的对象除了在数值上一样以外没有任何联系了,
被拷贝对象的值改变,拷贝出来的对象也不会受到影响了,就相当于克隆完之后你吃胖了,你克隆出来的那人还是那么瘦看着你笑一样的道理.
不知道注意到没有,我上面介绍概念的时候都是在用深拷贝和浅拷贝两个名词,并没有直接使用 cpoy 和 mutableCopy 两个名词,这是因为 copy并不是代表浅拷贝, mutableCopy 也不代表深拷贝,他们只是表明拷贝出来的对象是什么类型的,是可变还是不可变
下面详细说下cpoy 和 MutableCopy两个方法的区别:
讲解这两个方法我们分为两种情况一一去分析,最后再统一结果,这样更容易透彻的了解
一、对于不可变对象的 copy 和 mutableCopy分析
我们根据实际代码分析:
// 对于不可变字符串进行测试
NSString *string = @”asdfg”;
// copy 出可变和不可变两种字符串测试NSString *copyString = [string copy];NSMutableString *copyMutableString = [string copy];// mutableCopy 出可变和不可变两种字符串测试NSString *mutableCopyString = [string mutableCopy];NSMutableString *mutableCopyMutableString = [string mutableCopy];// 打印指针NSLog(@"========%p",string);NSLog(@"========%p",copyString);NSLog(@"========%p",copyMutableString);NSLog(@"========%p",mutableCopyString);NSLog(@"========%p",mutableCopyMutableString);
结果为:
2017-08-18 11:11:44.036 dailyTest[35812:7678186] ========0x100120160
2017-08-18 11:11:44.036 dailyTest[35812:7678186] ========0x100120160
2017-08-18 11:11:44.037 dailyTest[35812:7678186] ========0x100120160
2017-08-18 11:11:44.037 dailyTest[35812:7678186] ========0x610000075580
2017-08-18 11:11:44.037 dailyTest[35812:7678186] ========0x610000075480
结果可见:
对不可变对象使用 copy, 新拷贝出来的对象地址和被拷贝对象地址一致
对不可变对象使用 mutableCopy 新拷贝出来的对象和被拷贝的对象内存地址发生变化,
所以对不可变对象 copy 就是浅拷贝,mutableCopy 就是深拷贝.
同时需要注意:
NSMutableString *copyMutableString = [string copy];
在copyMutableString调用可变字符串方法的时候会发生崩溃,即使你在声明对象类型的时候声明成可变对象,但是使用 copy 方法拷贝出来的依旧是不可变对象,这也印证了我开头说的 copy 和 mutableCopy 只是代表拷贝出来的对象类型
二、对于可变对象的 copy 和 mutableCopy 分析
代码分析:
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@”uiipp”];
NSString *copyStringMutable = [mutableString copy];NSMutableString *copyMutableMutable = [mutableString copy];NSString *mutableCopyStringMutable = [mutableString mutableCopy];NSMutableString *mutableCopyMutableMutable = [mutableString mutableCopy];// 打印指针NSLog(@"********%p",mutableString);NSLog(@"********%p",copyStringMutable);NSLog(@"********%p",copyMutableMutable);NSLog(@"********%p",mutableCopyStringMutable);NSLog(@"********%p",mutableCopyMutableMutable);
结果:
2017-08-18 11:11:44.037 dailyTest[35812:7678186] ********0x100120200
2017-08-18 11:11:44.038 dailyTest[35812:7678186] ********0xa000070706969755
2017-08-18 11:11:44.038 dailyTest[35812:7678186] ********0xa000070706969755
2017-08-18 11:11:44.038 dailyTest[35812:7678186] ********0x600000078cc0
2017-08-18 11:11:44.038 dailyTest[35812:7678186] ********0x600000079400
结果分析对可变对象使用 copy 和MutableCopy 都会拷贝一个新的对象出来,即,copy 和 mutableCopy 都是深拷贝;
其他数据类型的结果分析和 NSString NSMutableString 一致,对于不可变类型 copy 是浅拷贝 ,mutableCopy 是深拷贝
对于可变类型都是深拷贝;
下面进行再深一层次的分析,对容器类例如(NSArray,NSDictionary )等,虽然以上结果依然成立,但是无论是浅拷贝还是深拷贝都只是相对于对象本身来说的,对于对象包含的元素并不进行拷贝,下面只测试数组一种类型的,其他相同:
测试代码:
// 不可变数组
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@”a”];
NSArray *array = @[mutableString, @”b”, @”c”, @”d”, @”e”];
// 容器类 + 不可变 + copyNSArray *copyArray = [array copy];NSMutableArray *mutableCopyArray = [array mutableCopy];NSLog(@"内存地址 :%p", array);NSLog(@"内存地址 :%p", copyArray);NSLog(@"内存地址 :%p", mutableCopyArray);NSLog(@"元素内存地址 :%p", array[0]);NSLog(@"元素内存地址 :%p", copyArray[0]);NSLog(@"元素内存地址 :%p", mutableCopyArray[0]);[mutableString appendString:@"sxxxx"];NSLog(@"############%@",array);NSLog(@"############%@",copyArray);NSLog(@"############%@",mutableCopyArray);
打印结果:
内存地址 :0x608000075340
2017-08-18 17:11:42.847 dailyTest[39274:8529843] 内存地址 :0x608000075340
2017-08-18 17:11:42.847 dailyTest[39274:8529843] 内存地址 :0x6080002413b0
2017-08-18 17:11:42.847 dailyTest[39274:8529843] 元素内存地址 :0x6080000753c0
2017-08-18 17:11:42.847 dailyTest[39274:8529843] 元素内存地址 :0x6080000753c0
2017-08-18 17:11:42.847 dailyTest[39274:8529843] 元素内存地址 :0x6080000753c0
2017-08-18 17:11:42.847 dailyTest[39274:8529843] ############(
asxxxx,
b,
c,
d,
e
)
2017-08-18 17:11:42.847 dailyTest[39274:8529843] ############(
asxxxx,
b,
c,
d,
e
)
2017-08-18 17:11:42.848 dailyTest[39274:8529843] ############(
asxxxx,
b,
c,
d,
e
)
结果分析显示:对象无论是深拷贝还是浅拷贝,对于其元素来说都是浅拷贝,并不进行深拷贝,当元素值被修改后,所有指向该元素地址的容器对象值都会改变
如果想对容器中包含的元素也进行深拷贝,则比较复杂:
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@”hahhah”];
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] init];[mutableDictionary setObject:mutableString forKey:@"key"];NSMutableArray *oldMutableArray = [[NSMutableArray alloc] initWithObjects:mutableDictionary, nil];NSMutableArray *newMutableArray = [[NSMutableArray alloc] initWithArray:oldMutableArray];NSMutableArray *copyItemMutableArray = [[NSMutableArray alloc] initWithArray:oldMutableArray copyItems:YES];// 做一遍归档接档NSData *data = [NSKeyedArchiver archivedDataWithRootObject:oldMutableArray];NSMutableArray *archiverArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];[mutableString appendString:@"asd********"];[mutableDictionary setObject:@"value" forKey:@"key_1"];NSLog(@"内存地址:$$$$$$$$$$$$$$%p", oldMutableArray); NSLog(@"内存地址:$$$$$$$$$$$$$$%p", newMutableArray);NSLog(@"内存地址:$$$$$$$$$$$$$$%p", copyItemMutableArray); NSLog(@"内存地址:$$$$$$$$$$$$$$%p", archiverArray);NSLog(@"元素内存地址:$$$$$$$$$$$$$$%p", oldMutableArray[0]); NSLog(@"元素内存地址:$$$$$$$$$$$$$$%p", newMutableArray[0]);NSLog(@"元素内存地址:$$$$$$$$$$$$$$%p", copyItemMutableArray[0]); NSLog(@"元素内存地址:$$$$$$$$$$$$$$%p", archiverArray[0]);NSLog(@"$$$$$$$$$$$$$$%@", oldMutableArray); NSLog(@"$$$$$$$$$$$$$$%@", newMutableArray);NSLog(@"$$$$$$$$$$$$$$%@", copyItemMutableArray); NSLog(@"$$$$$$$$$$$$$$%@", archiverArray);
打印结果:
2017-08-18 17:46:15.492 dailyTest[39505:8647738] 内存地址:
2017-08-18 17:46:15.493 dailyTest[39505:8647738] 内存地址:
2017-08-18 17:46:15.493 dailyTest[39505:8647738] 元素内存地址:
2017-08-18 17:46:15.493 dailyTest[39505:8647738] 元素内存地址:
2017-08-18 17:46:15.493 dailyTest[39505:8647738]
{
key = “hahhahasd********”;
“key_1” = value;
}
)
2017-08-18 17:46:15.493 dailyTest[39505:8647738]
{
key = hahhah;
}
)
通过打印结果知道:
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;方法只是对容易包含的第一层元素做一个深拷贝,
但是对于元素更深层次的数据则不会再做拷贝,所以也不是完全意义上的深拷贝,
通过归档解档方式实现可发现, string 改变后数组元素值没发生改变,并且元素字典设置新元素后,元素值也没改变,说明实现的是完全意义的深拷贝
以上代码都经过本人验证,
由于是自己一边学习一边测试整理,所以话语组织能力还有待提高,望谅解.
如有任何疑问或者讲解的地方有错误,欢迎提出,十分感谢
- IOS详解深拷贝和浅拷贝的概念、具体的使用以及对于容器类(NSArray,NSDictionary 等)和非容器类(NSString,NSdata 等)拷贝的差异
- ios下的深拷贝和浅拷贝概念
- 关于非容器类和容器类深浅拷贝的区分
- 浅拷贝和深拷贝 iOS 的copy 以及 mutablecopy
- iOS 关于容器类的浅、深拷贝探究
- iOS 深拷贝、浅拷贝(1)非容器类对象实例
- 类的赋值运算符=的重载,以及深拷贝和浅拷贝 详解
- 对于深拷贝和浅拷贝的理解
- NSString的copy属性分析 以及 深拷贝浅拷贝
- IOS深度拷贝,NSArray,NSDictionary的分类(Category)
- 浅拷贝和深拷贝,以及push_back()的奥秘【转】
- 浅拷贝和深拷贝,以及push_back()的奥秘【转】
- C++ 类的聚集和浅拷贝与深拷贝
- C++ 类的聚集和浅拷贝与深拷贝
- C++ 类的聚集和浅拷贝与深拷贝
- String类的浅拷贝和深拷贝
- Java的深拷贝和浅拷贝
- Java的深拷贝和浅拷贝
- jquery 时间戳转换日期格式
- JAVA使用堆外内存导致swap飙高
- java基础语法(顺便回顾cpp语法并比较与java的异同)
- FZU2277 Change(dfs序+树状数组)
- SIFT+BOW 实现图像检索
- IOS详解深拷贝和浅拷贝的概念、具体的使用以及对于容器类(NSArray,NSDictionary 等)和非容器类(NSString,NSdata 等)拷贝的差异
- 2017百度之星复赛:1006. Valley Numer(数位DP)
- 【整理】SIMD、MMX、SSE、AVX、3D Now!、neon——指令集大全
- 从头开始建立网站一
- Vue-webpack项目配置详解
- 在AS中的Termianl中使用git命令行管理git,提示不是‘git’不是内部或外部命令的解决办法
- linux VIM编辑器
- centos7挂载阿里oss到本地
- my异常