今天在一个技术群里看到关于copy
和mutableCopy
的讨论,感觉那个人说的不全面,今天顺便找个时间弄些例子重新总结下:
一、深拷贝就是拷贝对象本身到新的内存中,生成一个新的对象。浅拷贝就是拷贝指针,并不拷贝对象本身,原有的对象引用计数+1
二、非集合类对象copy与mutableCopy
NSString *str = @"123";
NSLog(@"%p", str);
NSString *copyStr = [str copy];
NSLog(@"%p", copyStr);
NSString *mutableCopyStr = [str mutableCopy];
NSLog(@"%p", mutableCopyStr);
2017-12-12 [2080:42478] 0x1076fa940
2017-12-12 [2080:42478] 0x1076fa940
2017-12-12 [2080:42478] 0x60400004e4f0
非集合类不可变对象的copy是浅拷贝,内存地址不变,mutableCopy是深拷贝
NSMutableString *str = [NSMutableString stringWithFormat:@"123"];
NSLog(@"%p", str);
NSString *copyStr = [str copy];
NSLog(@"%p", copyStr);
NSMutableString *mutableCopyStr = [str mutableCopy];
NSLog(@"%p", mutableCopyStr);
2017-12-12 [2174:48858] 0x6040002463f0
2017-12-12 [2174:48858] 0xa000000003332313
2017-12-12 [2174:48858] 0x60000024cc00
非集合类可变对象进行copy和mutableCopy都是深拷贝,内存地址发生改变。copy操作发生内存地址改变很好理解(从一个可变对象变成了不可变对象
),为什么mutableCopy也是深拷贝呢?猜测认为,可变对象后面有可能是要改变的,如果执行的是浅拷贝(指针拷贝),那么原对象或者mutableCopy出来的对象如果其中一个发生了改变,都会影响另外一个,所以应该是新创建一个对象。
三、集合类对象copy与mutableCopy
NSArray *array = @[@"123", @"asf"];
NSLog(@"%p", array);
NSArray *copyArray = [array copy];
NSLog(@"%p", copyArray);
NSMutableArray *mutableCopyArray = [array mutableCopy];
NSLog(@"%p", mutableCopyArray);
2017-12-12 [2340:64439] 0x604000039660
2017-12-12 [2340:64439] 0x604000039660
2017-12-12 [2340:64439] 0x6040000592c0
同非集合类对象,集合类不可变对象的copy也是浅拷贝,mutableCopy是深拷贝
NSMutableArray *array = [@[@"123", @"asf"] mutableCopy];
NSLog(@"%p", array);
NSArray *copyArray = [array copy];
NSLog(@"%p", copyArray);
NSMutableArray *mutableCopyArray = [array mutableCopy];
NSLog(@"%p", mutableCopyArray);
2017-12-12 [2392:70043] 0x60000024d4d0
2017-12-12 [2392:70043] 0x600000032fe0
2017-12-12 [2392:70043] 0x60000024c900
如上,不论是copy
还是mutableCopy
都对array进行了深拷贝。类似非集合类对象。
四、集合类的深拷贝
集合类的对象,在执行copy
或者mutableCopy
方法进行深拷贝的时候,仅仅是拷贝对象本身,对象内的元素仍然是浅拷贝(指针复制)
NSMutableString *string = [NSMutableString stringWithFormat:@"123"];
NSMutableArray *subArray = [@[@"123", @"adsf"] mutableCopy];
NSMutableArray *array = [NSMutableArray arrayWithObjects:string, subArray, nil];
NSArray *copyArray = [array copy];
NSLog(@"copyArray = %@", copyArray);
[string appendFormat:@"456"];
[subArray removeObjectAtIndex:0];
NSLog(@"copyArray = %@", copyArray);
2017-12-12 [3528:131325] copyArray= (
123,
(
123,
adsf
)
)
2017-12-12 [3528:131325] copyArray = (
123456,
(
adsf
)
)
如上,如果我们修改了copyArray
里面的string和subArray的话,copyArray内的对象也会跟着改变.
对集合内的对象也执行深拷贝可以使用如下两种方法:
NSArray *copyArray = [[NSArray alloc] initWithArray:array copyItems:YES];
NSMutableString *string = [NSMutableString stringWithFormat:@"123"];
NSMutableArray *subArray = [@[@"123", @"adsf"] mutableCopy];
NSMutableArray *array = [NSMutableArray arrayWithObjects:string, subArray, nil];
NSArray *copyArray = [[NSArray alloc] initWithArray:array copyItems:YES];
NSLog(@"copyArray = %@", copyArray);
[string appendFormat:@"456"];
[subArray removeObjectAtIndex:0];
NSLog(@"copyArray = %@", copyArray);
2017-12-12 [3625:137732] copyArray = (
123,
(
123,
adsf
)
)
2017-12-12 [3625:137732] copyArray = (
123,
(
123,
adsf
)
)
如上,发现copyArray内的对象并不会随着改变。但是如果集合内的对象里面的元素也改变了呢?
NSMutableString *string = [NSMutableString stringWithFormat:@"123"];
NSMutableArray *subArray = [@[string, @"adsf"] mutableCopy]; //这里在可变的数组里面加入可变的字符串string
NSMutableArray *array = [NSMutableArray arrayWithObjects:string, subArray, nil];
NSArray *copyArray = [[NSArray alloc] initWithArray:array copyItems:YES];
NSLog(@"copyArray = %@", copyArray);
[string appendFormat:@"456"];
[subArray removeObjectAtIndex:0];
NSLog(@"copyArray = %@", copyArray);
2017-12-12 [3687:144061] copyArray = (
123,
(
123,
adsf
)
)
2017-12-12 [3687:144061] copyArray = (
123,
(
123456,
adsf
)
)
这个时候我们发现如果array
内部的subArray
里面的string
发生了改变,是会影响到copyArray
的.
initWithXXXX: copyItems:
这个方法只能提供一层深拷贝,并不是真正的深拷贝。这个方法是对集合内每个对象都发送copyWithZone:
消息,如果集合内的对象遵守了NSCopying:
协议那么会深拷贝到新的集合对象内,如果没有遵守,会出错。
那么怎么才能实现完全深拷贝呢:
NSArray *deepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
这种将将集合进行归档(archive),然后再解档(unarchive),才可以实现完全深拷贝。
NSMutableString *string = [NSMutableString stringWithFormat:@"123"];
NSMutableArray *subArray = [@[string, @"adsf"] mutableCopy];
NSMutableArray *array = [NSMutableArray arrayWithObjects:string, subArray, nil];
NSArray *copyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
NSLog(@"copyArray = %@", copyArray);
[string appendFormat:@"456"];
[subArray removeObjectAtIndex:0];
NSLog(@"copyArray = %@", copyArray);
2017-12-12 [3736:149666] copyArray = (
123,
(
123,
adsf
)
)
2017-12-12 [3736:149666] copyArray = (
123,
(
123,
adsf
)
)
网友评论