一、概念:
浅复制,也有人称做浅拷贝。就是只改变新对象的指针指向,并未生成新的内存地址,只是将新对象的指针指向要复制对象的内存地址。集合类与非集合类执行copy操作都是浅复制。
深复制,同样也有人称做深拷贝。即改变新对象指针指向,还为对象生成新的内存地址。深复制又分为单层深复制与完全深复制,单层深复制虽然生成了新的内存地址,但是新的对象中的元素地址还是旧对象元素的地址;完全深复制就不一样了,不仅内存地址是新的,对象里面的元素地址也是新的。
二、非集合类对象:
1. 非集合类的copy操作:
NSString* stringHello = @"hello";
NSString* stringCopy = [stringHello copy];
NSLog(@"当前地址:%p---%p", stringHello, stringCopy); // 当前地址:0x104e9e288---0x104e9e288
NSMutableString* stringMu = [NSMutableString stringWithString:@"hello"];
NSString* stringMuCopy = [stringMu copy]; // 注意:copy产生新对象是NSString不是NSMutableString类型,切勿当做NSMutableString类型进行相关操作,不然会crash!
NSLog(@"当前地址:%p---%p", stringMu, stringMuCopy); // 当前地址:0x6040002566b0---0xa00006f6c6c65685
综上可得:
1. NSString类型的copy操作生成的新对象只是指向了旧对象的内存地址,并未产生新的内存地址,即进行了浅复制。
2. NSMutableString类型的copy操作产生新的内存地址生成NSString类型的对象,即进行了深复制。
2、非集合类的mutableCopy操作:
NSString* string = @"hello";
NSMutableString* muStr = [NSMutableString stringWithString:@"mjz"];
/** mutableCopy **/
NSMutableString* stringMuCopy = [string mutableCopy];
NSMutableString* muStringMuCopy = [muStr mutableCopy];
/** appendString拼接字符串 **/
[stringMuCopy appendString:@"jj"];
[muStringMuCopy appendString:@"zz"];
/**
* 打印结果:
* 地址1:string: 0x1046d10e8 , stringMuCopy :0x60c000056c80
* 地址2:muStr: 0x60c000056950 , muStringMuCopy :0x60c000055ea0
**/
NSLog(@"地址1:string: %p , stringMuCopy :%p", string, stringMuCopy);
NSLog(@"地址2:muStr: %p , muStringMuCopy :%p", muStr, muStringMuCopy);
综上可得:NSString与NSMutableString的mutableCopy操作都是深复制,产生新对象。
三、集合类对象:
1. 集合类的copy操作:
NSArray* array = @[@"jj", @"zz"];
NSArray* arrayCopy = [array copy];
NSLog(@"array:%p", array);
NSLog(@"arrayCopy:%p", arrayCopy);
NSMutableArray* muArray = [NSMutableArray arrayWithObjects:@"mm", @"jj", @"zz", nil];
NSArray* muArrayCopy = [muArray copy];
[muArray addObject:@"123"];
// [muArrayCopy addObject:@"123"]; // 崩溃,muArrayCopy为NSArray类型不是NSMutableArray类型
NSLog(@"muArray:%p", muArray);
NSLog(@"muArrayCopy:%p", muArrayCopy);
/* 打印结果:
array:0x604000032700
arrayCopy:0x604000032700
muArray:0x6000002585d0
muArrayCopy:0x600000258870
*/
综上可得:集合类的copy操作与非集合类copy操作基本一致,NSArray的copy操作是浅复制,NSMutableArray的copy操作是深复制。
2. 集合类的mutableCopy操作:
NSArray* array = @[@"mm", @"jj"];
NSMutableArray* arrayMuCopy = [array mutableCopy];
[arrayMuCopy addObject:@"hello"];
NSLog(@"array:%p", array);
NSLog(@"muArray:%p", arrayMuCopy);
NSMutableArray* muArray = [NSMutableArray arrayWithObjects:@"mm", @"jj", @"zz", nil];
NSMutableArray* muArrayMuCopy = [muArray mutableCopy];
[muArray addObject:@"tt"];
[muArrayMuCopy addObject:@"yy"];
NSLog(@"muArrayNew:%p", muArray);
NSLog(@"muArrayMuCopy:%p", muArrayMuCopy);
/* 打印结果:
array:0x60c000223540
muArray:0x60c0002403f0
muArrayNew:0x60400024c9c0
muArrayMuCopy:0x60400024cd80
*/
综上可得:集合类的copy操作与非集合类mutableCopy操作基本一致,都是深复制。
四、单层深复制
简述:以上的深复制只是产生了新的内存地址,但对象中的元素地址还是旧对象的地址。
NSArray* array = [NSArray arrayWithObject:@"hello"];
// NSMutableArray* array = [NSMutableArray arrayWithObject:@"hello"]; // 可开启调试NSMutableArray类型
NSArray* arrayCopy = [array copy];
NSMutableArray* arrayMu = [array mutableCopy];
NSString* stringElement = [array lastObject];
NSLog(@"对象元素地址1:%p---%p", array, stringElement);
NSString* stringCopyElement = [arrayCopy lastObject];
NSLog(@"对象元素地址2:%p---%p", arrayCopy, stringCopyElement);
NSString* stringMuElement = [arrayMu lastObject];
NSLog(@"对象元素地址3:%p---%p", arrayMu, stringMuElement);
/* 打印结果:
* 对象元素地址1:0x6040000179f0---0x10f4f60e8
* 对象元素地址2:0x6040000179f0---0x10f4f60e8
* 对象元素地址3:0x604000049db0---0x10f4f60e8
*/
综上可得:集合中元素地址并未发生变化。这里只测试集合类的测试,非集合类测试一样,所以不做赘述。
五、对象的复制
简述:要实现自定义对象的复制,需要遵守NSCopying,NSMutableCopying这两个协议,并实现copyWithZone与mutableCopyWithZone这两个方法。不过此复制也是单层深复制,要进行完全深复制,可进行归档解档实现,具体代码我写在一个类里。
@interface JZPerson : NSObject<NSCopying, NSMutableCopying, NSCoding>
@property (copy, nonatomic) NSString* name;
@property (copy, nonatomic) NSString* age;
@end
#import "JZPerson.h"
@implementation JZPerson
#pragma mark 复制实现
- (id)copyWithZone:(NSZone *)zone {
JZPerson* personObj = [[JZPerson allocWithZone:zone] init];
personObj.name = self.name;
personObj.age = self.age;
return personObj;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
JZPerson* personObj = [[JZPerson allocWithZone:zone] init];
personObj.name = self.name;
personObj.age = self.age;
return personObj;
}
#pragma mark 解档与归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.age forKey:@"age"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeObjectForKey:@"age"];
}
return self;
}
@end
/** 测试代码 **/
JZPerson* person = [[JZPerson alloc] init];
person.name = @"tsy";
person.age = @"11";
JZPerson* personCopy = [person copy];
JZPerson* personMuCopy = [person mutableCopy];
NSLog(@"%p---%p--%p", person, person.name, person.age);
NSLog(@"%p---%p--%p", personCopy, personCopy.name, personCopy.age);
NSLog(@"%p---%p--%p", personMuCopy, personMuCopy.name, personMuCopy.age);
JZPerson *personDeepCopy = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:person]];
NSLog(@"%p---%p--%p", personDeepCopy, personDeepCopy.name, personDeepCopy.age);
/* 打印结果:
* person:0x608000229460---0x10de0f548--0x10de0f208
* personCopy:0x608000229400---0x10de0f548--0x10de0f208
* personMuCopy:0x6080002294c0---0x10de0f548--0x10de0f208
* personDeepCopy:0x608000229420---0xa000000007973743--0xa000000000031312
*/
六、结论
1、不可变的集合类与非集合类的copy是浅复制,而mutableCopy则是深复制;
2、可变的集合类与非集合类的copy与mutableCopy都是深复制;
3、自定义对象复制为深复制,归档与解档可实现完全深复制。