集合对象可变与不可变的那点事
最近在看人工智能相关的知识,无意中发现了一个巨牛的 人工智能教程,分享一下给大家。
教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点 这里 可以直接看教程。
简介
在文章 NSString NSMutableString 可变与不可变的那些事儿 分享了关于 NSString
和 NSMutableString
与 copy
以及 mutableCopy
之间的点滴。
今天跟大家分享一下集合类数据的可变与不可变性,再结合 copy
以及 mutableCopy
说一说注意事项。如果你仔细看过 NSString NSMutableString 可变与不可变的那些事儿 这篇文章,那么接下来看本篇会很轻松。
本篇内容主要涉及以下几个方面:
- 在 OC 中的集合对象
- 集合对象的 copy、mutableCopy
- 可变与不可变集合对象之间等号赋值
- property 中的集合对象的 copy 和 strong
- 实际案例分析
为了说明问题,这里,我选用数组(NSArray)作为集合对象的代表,其他的集合类以此类推即可。
集合对象
在 Objective-C
中,非集合类对象指的是 NSString
、NSNumber
、NSValue
之类的对象,除了 NSString
有对应的可变类 NSMutableString
外,NSNumber
、NSValue
都没有可变类与其对应。
集合类对象是指 NSArray
、NSMutableArray
、 NSDictionary
、NSMutableDictionary
、NSSet
、NSMutableSet
之类的对象。
集合对象的 copy、mutableCopy
看一个具体例子,请接着看下面的示例代码和说明。
例子1:NSArray 的 copy、mutableCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| NSArray *array = [NSArray arrayWithObjects:@"veryitman.com", nil]; NSLog(@"array addr: %p, array: %@ ", array, array);
NSArray *array1 = array; NSLog(@"array1 addr: %p, array1: %@", array1, array1);
id array2 = [array copy]; NSLog(@"array2 addr: %p, array2: %@", array2, array2);
id array3 = [array mutableCopy]; NSLog(@"array3 addr: %p, array3: %@", array3, array3);
[(NSMutableArray *)(array3) addObject:@"my blog"]; NSLog(@"array3 addr: %p, array3: %@", array3, array3);
NSLog(@"array addr: %p, array: %@ ", array, array);
|
小结 1:
1、不可变数组 copy
之后,仍然是不可变数组,其地址和内容不变,即拷贝了原对象的内容和指针,属于指针拷贝。
2、不可变数组 mutableCopy
之后,变成了可变数组,其地址发生了变化,即只拷贝了原对象的内容,指针没有拷贝,属于内容拷贝。
3、不可变数组之间的等号(=)
赋值,是指针拷贝。
例子2:NSMutableArray 的 copy、mutableCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| NSMutableArray *marray = [NSMutableArray arrayWithObjects:@"veryitman.com", nil]; NSLog(@"marray addr: %p, marray: %@ ", marray, marray);
NSMutableArray *marray1 = marray; NSLog(@"marray1 addr: %p, marray1: %@ ", marray1, marray1);
id marray2 = [marray copy]; NSLog(@"marray2 addr: %p, marray2: %@ ", marray2, marray2);
id marray3 = [marray mutableCopy]; NSLog(@"marray3 addr: %p, marray3: %@ ", marray3, marray3);
[(NSMutableArray *)(marray3) addObject:@"my blog"]; NSLog(@"marray3 addr: %p, marray3: %@ ", marray3, marray3);
NSLog(@"marray addr: %p, marray: %@ ", marray, marray);
|
小结 2:
1、可变数组 copy
之后,会变成不可变数组,其内容不变,但是地址改变了,即只拷贝了原对象的内容,没有进行指针拷贝,属于内容拷贝。
2、可变数组 mutableCopy
之后,仍然是不可变数组,其地址发生了变化,内容没有变化,即只拷贝了原对象的内容,指针没有拷贝,属于内容拷贝。
3、可变数组之间等号(=)
赋值,是指针拷贝。
例子3:NSMutableArray 和 NSArray 之间等号赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| { NSMutableArray *tDatas = [NSMutableArray arrayWithObjects:@"veryitman.com", nil]; NSLog(@"--1--- tDatas addr: %p, tDatas: %@", tDatas, tDatas); NSArray *array = tDatas; NSLog(@"--2--- array addr: %p, array: %@", array, array); } { NSArray *tDatas = [NSArray arrayWithObjects:@"veryitman.com", nil]; NSLog(@"--1--- tDatas addr: %p, tDatas: %@", tDatas, tDatas); NSMutableArray *array = tDatas; NSLog(@"--2--- array addr: %p, array: %@", array, array); }
|
输出结果,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| --1--- tDatas addr: 0x6000023a8bd0, tDatas: ( "veryitman.com" ) --2--- array addr: 0x6000023a8bd0, array: ( "veryitman.com" )
--1--- tDatas addr: 0x600002dbbf00, tDatas: ( "veryitman.com" ) --2--- array addr: 0x600002dbbf00, array: ( "veryitman.com" )
|
以上是使用 NSArray
、NSMutableArray
来进行测试的,NSDictionary
和 NSSet
以及其对应的可变类型都遵循上面总结的内容。
copy、strong 修饰属性
在属性中,我们如何来选择 copy
或者 strong
来作为集合数据的修饰语呢?
根据上面示例分析结果可以看出,在属性中,如果使用 strong
修饰不可变数组,那么在使用过程中(被可变数组赋值)该不可变数组有可能会变为可变数组。如果使用 copy
修饰可变数组,那么在使用过程中(被不可变数组赋值)该可变数组有可能变为不可变数组。
小结 3:
当修饰可变类型的属性时,如 NSMutableArray
、NSMutableDictionary
、NSMutableSet
等集合类型时,用 strong
修饰。
当修饰不可变类型的属性时,如 NSArray
、NSDictionary
、NSSet
等集合类型时,用 copy
修饰。
大家如果有兴趣可以参考文章 NSString NSMutableString 可变与不可变的那些事儿 的做法来验证上面的理论知识。
实际案例分析
再给大家举个实际的开发案例,我们需要定时上报目采集APP的数据,这个需求看起来是没有任何难度的。
我们使用代码来模拟一下上报数据的这个过程。
1 2 3 4 5 6 7
| NSMutableDictionary *tDatas = [NSMutableDictionary dictionaryWithCapacity:5]; [tDatas setObject:@"https://" forKey:@"req_m"]; NSLog(@"--采集数据--- tDatas addr: %p, tDatas: %@", tDatas, tDatas);
[self sendDatas:tDatas]; NSLog(@"--上报完成,原数据--- tDatas addr: %p, tDatas: %@", tDatas, tDatas);
|
发送数据的模拟示例如下:
1 2 3 4 5 6 7 8 9 10 11
| - (void)sendDatas:(NSDictionary *)datas { NSLog(@"--上报中--- datas addr: %p, datas: %@", datas, datas); if ([datas isKindOfClass:[NSMutableDictionary class]]) { [(NSMutableDictionary *)datas setObject:@"veryitman.com" forKey:@"test_m"]; } NSLog(@"--上报完成--- datas addr: %p, datas: %@", datas, datas); }
|
根据上面例子3提到的,不可变向可变等号赋值时,原不可变对象会变成可变对象。
控制台输出日志,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| --采集数据--- tDatas addr: 0x600000b788e0, tDatas: { req_m = https: }
--上报中--- datas addr: 0x600000b788e0, datas: { req_m = https: }
--上报完成--- datas addr: 0x600000b788e0, datas: { req_m = https: test_m = veryitman.com; }
--上报完成,原数据--- tDatas addr: 0x600000b788e0, tDatas: { req_m = https: test_m = veryitman.com; }
|
下面代码的代码,我是为了模拟原数据被其他代码改变了的情况,只是为了说明,不可变对象容易被外界影响和改变。
1 2 3 4
| if ([datas isKindOfClass:[NSMutableDictionary class]]) { [(NSMutableDictionary *)datas setObject:@"veryitman.com" forKey:@"test_m"]; }
|
上面的总结又提到无论是可变对象还是不可变对象经过 copy
之后都是不可变对象的原理,我们修改一下代码,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| - (void)sendDatas:(NSDictionary *)datas { NSDictionary *copy_datas = [datas copy]; NSLog(@"--上报中--- copy_datas addr: %p, copy_datas: %@", copy_datas, copy_datas); if ([copy_datas isKindOfClass:[NSMutableDictionary class]]) { [(NSMutableDictionary *)copy_datas setObject:@"veryitman.com" forKey:@"test_m"]; } else { NSLog(@"Yes, copy_datas 是不可变字典。"); } NSLog(@"--上报完成--- copy_datas addr: %p, copy_datas: %@", copy_datas, copy_datas); }
|
输出结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| --采集数据--- tDatas addr: 0x600003b08740, tDatas: { req_m = https: }
--上报中--- copy_datas addr: 0x600003b08700, copy_datas: { req_m = https: }
Yes, copy_datas 是不可变字典。
--上报完成--- copy_datas addr: 0x600003b08700, copy_datas: { req_m = https: }
--上报完成,原数据--- tDatas addr: 0x600003b08740, tDatas: { req_m = https: }
|
扫码关注,期待与你的交流~