以前只知道copy操作过的对象,会得出一个新的不可变对象而mutableCopy操作过的对象,会得出一个新的可变对象,这篇文章算是对自己的误区的一个纠正,也是一个总结吧!
Copying Collections
拷贝分为深拷贝和浅拷贝;
深拷贝又分为完全拷贝和单层深拷贝;
浅拷贝(shallow copy)
浅拷贝指的是只拷贝对象的引用,而引用所指向的对象地址没有变还是同一个,只是对象的引用计数器+1了。
NSArray *array = @[@"1", @"2", @"3"];
NSArray *array2 = [array copy];
深拷贝(shallow copy)
完全拷贝()
完全深拷贝指的是当拷贝对象为集合时,即拷贝对象的地址,又拷贝对象内元素对象的地址;
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:aarray copyItems:YES];
单层深拷贝(one-level-deep copy)
单层深拷贝指的是只对拷贝集合对象的地址,没有拷贝集合内元素对象的地址。对此,苹果官网文档有这样一句话描述:
This kind of copy is only capable of producing a one-level-deep copy.
If you only need a one-level-deep copy, you can explicitly call for one as in Listing 2.
NSArray *array = @[self.string1, self.string2, self.string3];
NSArray *barray = [array copy];
非集合对象的深拷贝与浅拷贝
不可变对象(以NSString为例)
先看一个示例:
NSString *a = @"a";
NSString *b = [a copy];
NSMutableString *c = [a mutableCopy];
NSLog(@"A:%p", a);
NSLog(@"B:%p", b);
NSLog(@"C:%p", c);
结果:
A:0x100440078
B:0x100440078
C:0x60000025a910
不可变对象进行copy
操作时,实质上是进行的浅拷贝操作,并没有产生新对象;不可变对象进行mutableCopy
操作时,实质上是进行的深拷贝操作,并产生了新的可变对象。个人对不可变对象copy
操作的理解,因为对象是不可改变的没有必要copy
时产生一个新对象,同时也节约了内存空间。
不可变对象(以NSMutableString为例)
示例:
NSMutableString *a = [NSMutableString stringWithFormat:@"a"];
NSString *b = [a copy];
NSMutableString *c = [a mutableCopy];
NSLog(@"A:%p", a);
NSLog(@"B:%p", b);
NSLog(@"C:%p", c);
结果:
A:0x6040000541c0
B:0xa000000000000611
C:0x604000055150
可变对象进行copy
操作,实质上是进行了深拷贝操作,并产生了新的不可变对象;可变对象进行mutableCopy
操作,实质上也是进行了深拷贝操作,并产生了新的可变对象;
总结:
当copy
对象是不可变对象时,执行的是浅拷贝操作,当对象是可变对象时,执行的是深拷贝操作;而mutableCopy
操作都是进行的深拷贝操作。
集合对象的深拷贝与浅拷贝
不可变对象(以NSArray为例)
示例:
NSArray *aarray = @[self.string1, self.string2, self.string3];
NSArray *barray = [aarray copy];
NSMutableArray *carray = [aarray mutableCopy];
NSMutableArray *darray = [[NSMutableArray alloc] initWithArray:aarray copyItems:YES];
NSLog(@"Aarray:%p", aarray);
NSLog(@"Barray:%p", barray);
NSLog(@"Carray:%p", carray);
NSLog(@"Darray:%p", darray);
for (NSString *i in aarray) {
NSLog(@"subA--:%p", i);
}
for (NSString *i in barray) {
NSLog(@"subB--:%p", i);
}
for (NSString *i in carray) {
NSLog(@"subC--:%p", i);
}
for (NSString *i in darray) {
NSLog(@"subD--:%p", i);
}
结果:
Aarray:0x604000452c60
Barray:0x604000452c60
Carray:0x604000452c00
Darray:0x604000453fb0
subA--:0x60400044dd40
subA--:0x604000450320
subA--:0x604000452d80
subB--:0x60400044dd40
subB--:0x604000450320
subB--:0x604000452d80
subC--:0x60400044dd40
subC--:0x604000450320
subC--:0x604000452d80
subD--:0xa000000000000611
subD--:0xa000000000000621
subD--:0xa000000000000631
当对不可变集合对象进行copy
操作时,只是拷贝了集合对象的指针,并没有对对象的地址进行拷贝,也没有对对象内的元素进行拷贝;当对不可变集合对象进行mutableCopy
操作时,拷贝了对象的地址,但是没有对对象内的元素对象地址进行拷贝;当对不可变集合对象进行initWithArray:copyItems:
操作时,通过重新创建集合对象,设置copyItems
为YES
,对集合内的元素对象进行了拷贝。
可变对象(以NSMutableArray为例)
示例:
NSMutableArray *aarray = [NSMutableArray arrayWithObjects:self.string1, self.string2, self.string3, nil];
NSArray *barray = [aarray copy];
NSMutableArray *carray = [aarray mutableCopy];
NSMutableArray *darray = [[NSMutableArray alloc] initWithArray:aarray copyItems:YES];
NSLog(@"Aarray:%p", aarray);
NSLog(@"Barray:%p", barray);
NSLog(@"Carray:%p", carray);
NSLog(@"Darray:%p", darray);
for (NSString *i in aarray) {
NSLog(@"subA--:%p", i);
}
for (NSString *i in barray) {
NSLog(@"subB--:%p", i);
}
for (NSString *i in carray) {
NSLog(@"subC--:%p", i);
}
for (NSString *i in darray) {
NSLog(@"subD--:%p", i);
}
结果:
Aarray:0x60000025c140
Barray:0x60000025ac10
Carray:0x600000259ad0
Darray:0x600000258d50
subA--:0x604000251df0
subA--:0x604000251cd0
subA--:0x604000251610
subB--:0x604000251df0
subB--:0x604000251cd0
subB--:0x604000251610
subC--:0x604000251df0
subC--:0x604000251cd0
subC--:0x604000251610
subD--:0xa000000000000611
subD--:0xa000000000000621
subD--:0xa000000000000631
当对可变集合对象进行copy
操作时,对对象的地址进行拷贝,但没有对对象内的元素进行拷贝;当对可变集合对象进行mutableCopy
操作时,拷贝了对象的地址,但是没有对对象内的元素对象地址进行拷贝;当对可变集合对象进行initWithArray:copyItems:
操作时,通过重新创建集合对象,设置copyItems
为YES
,对集合内的元素对象进行了拷贝。