文章目录
  1. 1. 拷贝和拷贝协议
    1. 1.1. Copy和NSCopying协议
    2. 1.2. mutableCopy和NSMutableCopying协议
    3. 1.3. copy 与 mutableCopy的逻辑
  2. 2. 拷贝的分类
    1. 2.1. 指针拷贝和对象拷贝(内容拷贝)
    2. 2.2. 深拷贝和浅拷贝
  3. 3. 对NSArray的拷贝测试
  4. 4. @property中的copy,mutalecopy关键字

拷贝和拷贝协议

Copy和NSCopying协议

使用对象时经常需要拷贝它。在Objective-C中,此操作是通过copy方法完成的。如果想让自己的类(继承自NSObject,假设叫CustomClass)支持拷贝操作。则需要让自定义类遵循NSCopying协议(NSObject并未遵循该协议):

1
2
3
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end

简单来说,当对某个对象发送copy消息时,NSObject#copy的实现逻辑会去自动调用copyWithZone:方法,有点回调的感觉;因此,若想支持拷贝操作,需要在自定义类中让其支持NSCopying并实现copyWithZone:方法,并不是重写copy方法。

mutableCopy和NSMutableCopying协议

它们俩与copy方法和NSCopying协议相对应。当你的类还有mutable版本时,你还应该遵循NSMutableCopying协议,并实现mutableCopyWithZone:方法,这样,当向该类对象发送mutableCopy消息时,NSObject的mutableCopy方法实现代码中会回调你的mutableCopyWithZone:方法。

copy 与 mutableCopy的逻辑

执行拷贝后返回对象的规则

1
2
3
4
5
6
7
8
9
10
11
// 向immutable对象发送copy消息,得到一个immutable对象
[CustomClass copy]; //-> CustomClass

// 向mutable对象发送一个copy消息,得到一个immutable对象
[MutableCustomClass copy]; //-> CustomClass

// 向immutable对象发送mutableCopy消息,得到mutable对象
[CustomClass mutableCopy];// -> MutableCustomClass

// 向mutable对象发送mutableCopy消息,得到mutable对象
[MutableCustomClass mutableCopy];// -> MutableCustomClass

拷贝的分类

指针拷贝和对象拷贝(内容拷贝)

  • 指针拷贝:不创建新对象,只是创建一个新的指针指向被拷贝的对象。
  • 对象拷贝:根据被拷贝对象创建一个新对象作为一份拷贝,新建指针指向新对象。

向immutable对象发送copy消息一定会得到一个新对象吗?

通过测试,NSString、NSArray、NSDictionary以及NSSet,这是我们最常用的四个含有mutable版本的类型;向这些类型的immutable对象发送copy消息,这些对象会直接返回本身,而不是返回一个新创建的对象。

深拷贝和浅拷贝

一般来说,「深拷贝」和「浅拷贝」这两个概念是分析集合类型才会谈及的。

  • 深拷贝:在拷贝对象时,将其底层数据也一并复制过去。Foundation框架中所有集合类型在默认情况下都执行浅拷贝,也就是说,只拷贝容器对象本身,而不复制其中数据。这样做的原因在于,容器内的对象未必能拷贝,而且调用者也未必想在拷贝容器时一并拷贝其中每一个对象。
  • 浅拷贝:在拷贝对象时,只将底层数据的指针复制过去。

对NSArray的拷贝测试

下面是对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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
NSArray *array = @[@"1",[[NSMutableString alloc]initWithString:@"abc"]];

[((NSMutableString *)array[1]) appendString:@"d"];

NSLog(@"****");
NSLog(@"array %p, & %p", array, &array);
for (id item in array) {
NSLog(@"array_i - %p & %p",item, &item);
NSLog(@"item class : %@",[item class]);
}

//打印结果
//FDCopy.m:73 array 0x61800002ec00, & 0x7fff58ae5080
//FDCopy.m:75 array_i - 0x10711f3a8 & 0x7fff58ae5078
//FDCopy.m:75 array_i - 0x61800006ae80 & 0x7fff58ae5078

NSLog(@"\n ****");
NSArray *arrayCopy = [array copy];
NSLog(@"arrayCopy %p", arrayCopy);
for (id item in arrayCopy) {
NSLog(@"arrayCopy_i - %p & %p",item, &item);
}

//打印结果
//FDCopy.m:80 arrayCopy 0x61800002ec00
//FDCopy.m:82 arrayCopy_i - 0x10711f3a8 & 0x7fff58ae5028
//FDCopy.m:82 arrayCopy_i - 0x61800006ae80 & 0x7fff58ae5028
//结论:[array copy]; 指针拷贝,浅拷贝

NSLog(@"\n ****");
NSMutableArray *arrayMCopy = [array mutableCopy];
NSLog(@"arrayMCopy %p", arrayMCopy);
for (id item in arrayMCopy) {
NSLog(@"arrayMCopy - %p & %p",item, &item);
}

//打印结果
//FDCopy.m:87 arrayMCopy 0x618000044bc0
//FDCopy.m:89 arrayMCopy - 0x10711f3a8 & 0x7fff58ae4fd8
//FDCopy.m:89 arrayMCopy - 0x61800006ae80 & 0x7fff58ae4fd8

//结论:[array mutableCopy]; 内容拷贝,浅拷贝

arrayMCopy = [arrayMCopy mutableCopy];
NSLog(@"\n ****");
NSLog(@"arrayMCopy %p", arrayMCopy);
for (id item in arrayMCopy) {
NSLog(@"arrayMCopy - %p & %p",item, &item);
NSLog(@"item class : %@",[item class]);
}

// [mutableArray mutableCopy]; 内容拷贝,浅拷贝

基于以上测试的结论:

  • [array copy]:指针拷贝,浅拷贝
  • [array mutableCopy]: 内容拷贝,浅拷贝
  • [mutableArray mutableCopy]:内容拷贝,浅拷贝

@property中的copy,mutalecopy关键字

并不确定是指针拷贝还是对象拷贝,或是深拷贝与浅拷贝,只是执行了对应类的copy或mutalecopy函数。