OC学习25:copy和mutableCopy探索

张建 lol

简介

Objective-C 对象是通过指向该对象内存地址的指针,以 间接 方式访问的。

指针赋值

  • MRC 下仅仅将一个新的指针指向该内存地址,并没有获取该内存的所有权,引用计数不变;

  • ARC 下由于默认使用 strong 修饰,因此将一个新的指针指向该内存地址,获取该内存的所有权,引用计数+1;

概念

对于实现了NSCopying与NSMutableCopying协议的对象来说,指针赋值并非简单的赋值,还有额外的操作:

  1. 浅拷贝

类似于ARC下的指针赋值,将一个新指针指向该内存地址;

  1. 深拷贝

将一个新指针指向新的内存对象,该内存的数据与被复制的数据相同!如果改变原内存数据,新对象不会随着改变!

非容器类:字符串

注:__NSCFConstantString 代表不可变,__NSCFString 代表可变

  1. 不可变字符串NSString
1
2
3
4
5
6
7
8
9
10
11
12
// 不可变的字符串
NSString *string = @"string";
NSString *string_1 = [string copy];
NSMutableString *string_2 = [string mutableCopy];
NSLog(@"string : %@ %p",[string class],string);
NSLog(@"string_1 : %@ %p",[string_1 class],string_1);
NSLog(@"string_2 : %@ %p",[string_2 class],string_2);

******打印结果******
2020-08-12 20:10:15.022910+0800 OC-copy和mutableCopy[39668:2403350] string : __NSCFConstantString 0x10a9bd028
2020-08-12 20:10:15.023183+0800 OC-copy和mutableCopy[39668:2403350] string_1 : __NSCFConstantString 0x10a9bd028
2020-08-12 20:10:15.023983+0800 OC-copy和mutableCopy[39668:2403350] string_2 : __NSCFString 0x600000e395c0

由结果可知:
copy指向同一个内存地址,指针拷贝,即浅拷贝,返回不可变类型
mutable指向不同的内存地址,深拷贝,返回可变类型

  1. 可变字符串NSMutableString
1
2
3
4
5
6
7
8
9
10
11
12
//可变的字符串
NSMutableString * mutableStr = [NSMutableString stringWithString:@"mutableStr"];
NSMutableString *mutableString_1 = [mutableStr copy];
NSMutableString *mutableString_2 = [mutableStr mutableCopy];
NSLog(@"mutableStr : %@ %p",[mutableStr class],mutableStr);
NSLog(@"mutableString_1 : %@ %p",[mutableString_1 class],mutableString_1);
NSLog(@"mutableString_2 : %@ %p",[mutableString_2 class],mutableString_2);

******打印结果******
2020-08-12 20:11:36.024015+0800 OC-copy和mutableCopy[39698:2404773] mutableStr : __NSCFString 0x600003bf9d10
2020-08-12 20:11:36.024163+0800 OC-copy和mutableCopy[39698:2404773] mutableString_1 : __NSCFString 0x6000035f5400
2020-08-12 20:11:36.024275+0800 OC-copy和mutableCopy[39698:2404773] mutableString_2 : __NSCFString 0x600003bf9e60

由结果可知:
copy指向不同的内存地址,深拷贝,返回可变类型
mutable指向不同的内存地址,深拷贝,返回可变类型

容器类:

数组

  1. 不可变数组

注: __NSArrayI 代表不可变,__NSArrayM 代表可变

1
2
3
4
5
6
7
8
9
10
11
12
//不可变数组
NSArray *arr = @[@"1",@"2"];
NSArray *arr_1 = arr.copy;
NSMutableArray *arr_2 = arr.mutableCopy;
NSLog(@"arr : %@ %p",[arr class],arr);
NSLog(@"arr_1 : %@ %p %p",[arr_1 class],arr_1,arr_1[0]);
NSLog(@"arr_2 : %@ %p %p",[arr_2 class],arr_2,arr_2[0]);

******打印结果******
2020-08-25 17:52:40.585722+0800 OC-copy和mutableCopy[43144:2152457] arr : __NSArrayI 0x600000a6b8e0
2020-08-25 17:52:40.585927+0800 OC-copy和mutableCopy[43144:2152457] arr_1 : __NSArrayI 0x600000a6b8e0 0x101024128
2020-08-25 17:52:40.586054+0800 OC-copy和mutableCopy[43144:2152457] arr_2 : __NSArrayM 0x600000471980

由上面的结果可知:
copy指向同一个内存地址,浅拷贝,返回不可变类型
mutableCopy指向不同的内存地址,深拷贝,返回可变类型
不可变数组中的元素指向同一个内存地址,浅拷贝

  1. 可变数组
1
2
3
4
5
6
7
8
9
10
11
12
//可变数组
NSMutableArray * mutableArr = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
NSArray *mutableArr_1 = mutableArr.copy;
NSMutableArray *mutableArr_2 = mutableArr.mutableCopy;
NSLog(@"mutableArr : %@ %p",[mutableArr class],mutableArr);
NSLog(@"copyArr_1 : %@ %p %p",[mutableArr_1 class],mutableArr_1,mutableArr_1[0]);
NSLog(@"mutableCopyArr_2 : %@ %p %p",[mutableArr_2 class],mutableArr_2,mutableArr_2[0]);

******打印结果******
2020-08-25 17:52:40.586501+0800 OC-copy和mutableCopy[43144:2152457] mutableArr : __NSArrayM 0x600000479230
2020-08-25 17:52:40.587261+0800 OC-copy和mutableCopy[43144:2152457] copyArr_1 : __NSArrayI 0x600000a05ec0 0x101024128
2020-08-25 17:52:40.587486+0800 OC-copy和mutableCopy[43144:2152457] mutableCopyArr_2 : __NSArrayM 0x6000004790b0 0x101024128

由上面的结果可知:
copy指向不同的内存地址,深拷贝,返回不可变类型
mutableCopy指向不同的内存地址,深拷贝,返回可变类型
可变数组中的元素指向同一个内存地址,浅拷贝

字典

  1. 不可变字典
1
2
3
4
5
6
7
8
9
10
11
12
//不可变字典
NSDictionary *dic = @{@"1":@"z",@"2":@"j"};
NSDictionary *dic_1 = dic.copy;
NSMutableDictionary *dic_2 = dic.mutableCopy;
NSLog(@"dic : %@ %p",[dic class],dic);
NSLog(@"dic_1 : %@ %p %p",[dic_1 class],dic_1,dic_1[@"1"]);
NSLog(@"dic_2 : %@ %p %p",[dic_2 class],dic_2,dic_2[@"1"]);

******打印结果******
2020-08-25 18:02:07.764010+0800 OC-copy和mutableCopy[43252:2160581] dic : __NSDictionaryI 0x600002acbac0
2020-08-25 18:02:07.764194+0800 OC-copy和mutableCopy[43252:2160581] dic_1 : __NSDictionaryI 0x600002acbac0 0x10f0cb228
2020-08-25 18:02:07.764331+0800 OC-copy和mutableCopy[43252:2160581] dic_2 : __NSDictionaryM 0x600003fb1ea0 0x10f0cb228

由结果可知:
copy指向同一个内存地址,浅拷贝,返回不可变类型
mutableCopy指向不同的内存地址,深拷贝,返回可变类型
不可变字典中的元素指向同一个内存地址,浅拷贝

  1. 可变字典
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//可变字组
NSMutableDictionary * mutableDic = [NSMutableDictionary dictionaryWithDictionary:@{@"1":@"z",@"2":@"z"}];
NSArray *mutableDic_1 = mutableDic.copy;
NSMutableArray *mutableDic_2 = mutableDic.mutableCopy;
//可变字典
NSMutableDictionary * mutableDic = [NSMutableDictionary dictionaryWithDictionary:@{@"1":@"z",@"2":@"z"}];
NSDictionary *mutableDic_1 = mutableDic.copy;
NSMutableDictionary *mutableDic_2 = mutableDic.mutableCopy;
NSLog(@"mutableDic : %@ %p",[mutableDic class],mutableDic);
NSLog(@"mutableDic_1 : %@ %p %p",[mutableDic_1 class],mutableDic_1,mutableDic_1[@"1"]);
NSLog(@"mutableDic_2 : %@ %p %p",[mutableDic_2 class],mutableDic_2,mutableDic_2[@"1"]);

******打印结果******
2020-08-25 18:03:42.698800+0800 OC-copy和mutableCopy[43295:2162720] mutableDic : __NSDictionaryM 0x6000023efb00
2020-08-25 18:03:42.699266+0800 OC-copy和mutableCopy[43295:2162720] mutableDic_1 : __NSFrozenDictionaryM 0x6000023ef8a0 0x10602a228
2020-08-25 18:03:42.699646+0800 OC-copy和mutableCopy[43295:2162720] mutableDic_2 : __NSDictionaryM 0x6000023ef800 0x10602a228

由结果可知:
copy指向不同的内存地址,深拷贝,返回不可变类型
mutableCopy指向不同的内存地址,深拷贝,返回可变类型
可变字典中的元素指向同一个内存地址,浅拷贝

非容器类:自定义对象

要支持copy与mutableCopy,需要实现NSCopying,NSMutableCopying协议。
(Foundation框架对象都实现了该协议,所以可以直接使用copy与mutableCopy,UIKit框架不可以)
用法如下:

自定义person类中实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@interface Person @interface Person : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic,copy)NSString * name;
@property (nonatomic,assign)int age;
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
Person *person = [Person allocWithZone:zone];
person.name = self.name;
person.age = self.age;
return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
Person *person = [Person allocWithZone:zone];
person.name = self.name;
person.age = self.age;
return person;
}
@end

调用:

1
2
3
4
5
6
7
8
9
10
11
12
// 简单的调用代码
Person *person = [[Person alloc] init];
Person *copyPerson = [person copy];
Person *mutableCopyPerson = [person mutableCopy];
NSLog(@"person : %@ %p",[person class],person);
NSLog(@"copyPerson : %@ %p",[copyPerson class],copyPerson);
NSLog(@"mutableCopyPerson : %@ %p",[mutableCopyPerson class],mutableCopyPerson);

*******打印结果********
2020-08-12 20:49:20.832411+0800 OC-copy和mutableCopy[40043:2426556] person : Person 0x600000e7f500
2020-08-12 20:49:20.832594+0800 OC-copy和mutableCopy[40043:2426556] copyPerson : Person 0x600000e7f540
2020-08-12 20:49:20.832703+0800 OC-copy和mutableCopy[40043:2426556] mutableCopyPerson : Person 0x600000e7f680

由结果可知:
copy指向不同的内存地址,深拷贝,返回本类
mutableCopy指向不同的内存地址,深拷贝,返回本类

总结

注:容器类中的元素都是浅拷贝,因为指向同一个内存地址

  • Post title:OC学习25:copy和mutableCopy探索
  • Post author:张建
  • Create time:2020-08-12 06:54:44
  • Post link:https://redefine.ohevan.com/2020/08/12/OC/OC学习25:copy和mutableCopy探索/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.