深拷贝与浅拷贝

前几天在做项目的时候遇到了一个比较坑爹的问题,情况可以用下面代码来示意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)viewDidLoad {
[super viewDidLoad];

self.cache = [[NSCache alloc] init];
DMUser *user = [DMUser new];
user.name = @"Tom";
user.age = 18;
user._id = @1;

[self.cache setObject:user forKey:user._id];

DMUser *fetchUser = [self fetchUserForId:@1];
fetchUser.name = @"John";

DMUser *fetchUser1 = [self fetchUserForId:@1];
NSLog(@"fetchUser1 = %@",fetchUser1.name);//fetchUser1 = John

}

- (DMUser *)fetchUserForId:(NSNumber *)userId
{
DMUser *fetchUser = [self.cache objectForKey:userId];
return fetchUser;
}

从cache中取出的数据做了修改后,cache中保存的数据同样被修改了,这不是我们想要的结果。要想知道为什么,就需要了解一下拷贝相关知识。

拷贝分为深拷贝和浅拷贝两种,深拷贝和浅拷贝的区别如下:

类型 是否开辟新的内存空间 是否影响引用计数
深拷贝
浅拷贝

不同拷贝方式产生结果:

源对象类型 拷贝方式 目标对象 拷贝类型(深/浅)
mutable对象 copy 不可变 深拷贝
mutable对象 mutableCopy 可变 深拷贝
非mutable对象 copy 不可变 浅拷贝
非mutable对象 mutableCopy 可变 深拷贝

可变对象的copy和mutableCopy都是深拷贝
不可变对象的copy是浅拷贝,mutableCopy是深拷贝
copy方法返回的都是不可变对象

对于集合类型的进行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
30
31
32
- (void)test1
{
NSString *str1 = @"hello";
NSString *str2 = @"world";

NSArray *arr = @[str1,str2];

NSLog(@"%p==%p",arr.firstObject,arr[1]);
NSMutableArray *mutableArr = [arr copy];//与[arr mutableCopy]效果一样
str1 = @"hello---";
NSLog(@"%p==%p;%@==%@",mutableArr.firstObject,mutableArr[1],mutableArr.firstObject,arr.firstObject);
/*
0x102f64108==0x102f64188
0x102f64108==0x102f64188;hello==hello
*/
}

- (void)test2
{
NSMutableString *mutableStr1 = [[NSMutableString alloc] initWithString:@"hello"];
NSMutableString *mutableStr2 = [[NSMutableString alloc] initWithString:@"world"];
NSMutableArray *mutableArr = [[NSMutableArray alloc] initWithObjects:mutableStr1,mutableStr2, nil];
NSLog(@"%p==%p",mutableArr.firstObject,mutableArr[1]);

NSArray *mutableCopyArr = [mutableArr copy];//与[mutableArr copy]效果一样
[mutableStr1 appendString:@"--"];
NSLog(@"%p==%p==%p==%p;%@==%@",mutableArr.firstObject,mutableArr[1],mutableCopyArr.firstObject,mutableCopyArr[1],mutableArr.firstObject,mutableCopyArr.firstObject);
/*
0x600000241fb0==0x6000002402a0
0x600000241fb0==0x6000002402a0==0x600000241fb0==0x6000002402a0;hello--==hello--
*/
}

Demo