1,深拷贝:内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区域。(另外创建一个一摸一样的对象,新对象与原对象不共享内存,修改新对象不会改变原对象)
2,浅拷贝:指针拷贝,复制一个新指针,指针指向同一块内存区域。实际内存并没有发生拷贝(只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存)
深拷贝图像示意
浅拷贝图像示意
在Objective-C中并不是所有的对象(自定义类创建的对象)都支持Copy,MutableCopy,遵守NSCopying协议的类才可以发送Copy消息,遵守NSMutableCopying 协议的类才可以发送MutableCopy消息。
以NSString类型为例
NSString *string1 = @"helloworld";
NSString *string2 = [string1 copy];
NSString *string3 = [string1 mutableCopy];
NSMutableString *string4 = [string1 copy];
NSMutableString *string5 = [string1 mutableCopy];
NSLog(@"string1 = %p",string1);
NSLog(@"string2 = %p",string2);
NSLog(@"string3 = %p",string3);
NSLog(@"string4 = %p",string4);
NSLog(@"string5 = %p",string5);
string2和string4进行了浅拷贝,复制对象和被复制对象都不可改变,所以只复制了指针。
string3和string5进行了深拷贝,为了保证复制对象可以改变,所以即复制了指针又复制了所指的内容
NSMutableString *string1 = [NSMutableString stringWithString:@"helloworld"];
NSString *string2 = [string1 copy];
NSString *string3 = [string1 mutableCopy];
NSMutableString *string4 = [string1 copy];
NSMutableString *string5 = [string1 mutableCopy];
NSLog(@"string1 = %p",string1);
NSLog(@"string2 = %p",string2);
NSLog(@"string3 = %p",string3);
NSLog(@"string4 = %p",string4);
NSLog(@"string5 = %p",string5);
string2到string5都进行了深拷贝,为了保证被复制对象可以改变,无论复制对象是否可以改变,都复制了指针又复制了所指的内容 。
总结:
对immutable对象进行copy操作,是浅拷贝,mutablecopy操作时,是深拷贝;对mutabled对象进行copy和mutable copy,都是深拷贝。
集合对象包括NSArray,NSSet,NSDictionary等类的对象
以NSArray为例
NSArray *array01 = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];
NSArray *copyArray01 = [array01 copy];
NSMutableArray *mutableCopyArray01 = [array01 mutableCopy];
NSLog(@"array01 = %p", array01);
NSLog(@"copyArray01 = %p", copyArray01);
NSLog(@"mutableCopyArray01 = %p", mutableCopyArray01);
NSLog(@"array01[0] = %p", array01[0]);
NSLog(@"copyArray01[0] = %p", copyArray01[0]);
NSLog(@"mutableCopyArray01[0] = %p", mutableCopyArray01[0]);
copyArray01进行了浅拷贝,复制对象和被复制对象都不可改变,所以只复制了指针。
mutableCopyArray01进行了深拷贝,为了保证复制对象可以改变,所以即复制了指针又复制了所指的内容 。
copyArray01和mutableCopyArray01集合内部的元素仍然是指针拷贝(浅拷贝)。
NSMutableArray *mutableArray01 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil];
NSArray *copyArray01 = [mutableArray01 copy];
NSMutableArray *mutableCopyArray01 = [mutableArray01 mutableCopy];
NSLog(@"mutableArray01 = %p", mutableArray01);
NSLog(@"copyArray01 = %p", copyArray01);
NSLog(@"mutableCopyArray01 = %p", mutableCopyArray01);
[mutableArray01 addObject:@"d"];
NSLog(@"mutableArray01 = %@", mutableArray01);
NSLog(@"copyArray01 = %@", copyArray01);
NSLog(@"mutableCopyArray01 = %@", mutableCopyArray01);
NSLog(@"mutableArray01[0] = %p", mutableArray01[0]);
NSLog(@"copyArray01[0] = %p", copyArray01[0]);
NSLog(@"mutableCopyArray01[0] = %p", mutableCopyArray01[0]);
copyArray01和mutableCopyArrat01都进行了深拷贝,为了保证被复制对象可以改变,无论复制对象是否可以改变,都复制了指针又复制了所指的内容 。
由于mutableArray是可变类型,可以对其集合添加元素,其集合里面的元素会增加,而copyArray01和mutableCopyArrat01都进行了深拷贝,它们集合里面的元素不会增加。
copyArray01和mutableCopyArray01集合内部的元素仍然是指针拷贝(浅拷贝)。
总结:
在集合类对象中,对immutable对象进行copy,是浅拷贝,mutableCopy是深拷贝;对mutable对象进行copy和mutableCopy都是深拷贝。但是:集合对象的内容拷贝仅限于对象本身,对象元素仍然是浅拷贝。
那么怎么对集合里面的元素也进行深拷贝呢?
完全拷贝(real-deep copy):在完全拷贝操作时,对于被拷贝对象的每一层都是对象拷贝。
例如数组完全深拷贝需要执行initWithArray:copyItems: 方法
NSArray *deepCopy = [[NSArray alloc] initWithArray:array copyItems:YES]
我们要想对数组中的对象也进行深拷贝,要做到如下:
首先创建Person.h
和Person.m,
需要实现
协议。
Person.h
#import
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (nonatomic, strong) NSMutableString* name;
@end
NS_ASSUME_NONNULL_END
Person.m
#import "Person.h"
@implementation Person
@synthesize name;
- (id) copyWithZone:(NSZone *)zone {
Person* person = [[[self class] allocWithZone:zone] init];
person.name = [self.name mutableCopy];
return person;
}
@end
maim.n
#import
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
/*--------数组元素拷贝-------*/
NSLog(@"");
NSLog(@"--不可变NSArray--元素拷贝--");
Person *person = [[Person alloc] init];
person.name = [NSMutableString stringWithString:@"one"];
NSArray *array1 = [[NSArray alloc] initWithObjects:person, nil];
//注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];
NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
Person *p = array2[0];
[p.name replaceCharactersInRange:NSMakeRange(0, 3) withString:@"two"];
//获取两个数组里的各自Person对象
Person *p1 = [array1 objectAtIndex:0];
Person *p2 = [array2 objectAtIndex:0];
NSLog(@"array1:%p",array1);
NSLog(@"array2:%p",array2);
NSLog(@"p1:%p",p1);
NSLog(@"p2:%p",p2);
NSLog(@"p1.name1:%p",p1.name);
NSLog(@"p2.name2:%p",p2.name);
NSLog(@"p1.name:%@",p1.name);
NSLog(@"p2.name:%@",p2.name);
NSLog(@"");
NSLog(@"--可变NSMutableArray--元素拷贝--");
Person *per = [[Person alloc] init];
per.name = [NSMutableString stringWithString:@"one11"];
NSMutableArray *array111 = [[NSMutableArray alloc] initWithObjects:person, nil];
//注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];
NSMutableArray *array222 = [[NSMutableArray alloc] initWithArray:array111 copyItems:YES];
Person *pp = array222[0];
[pp.name replaceCharactersInRange:NSMakeRange(0, 3) withString:@"two11"]; //获取两个数组里的各自Person对象
Person *p11 = [array111 objectAtIndex:0];
Person *p22 = [array222 objectAtIndex:0];
NSLog(@"array111:%p",array111);
NSLog(@"array222:%p",array222);
NSLog(@"p11:%p",p11);
NSLog(@"p22:%p",p22);
NSLog(@"p11.name:%@",p11.name);
NSLog(@"p22.name:%@",p22.name);
}
return 0;
}
我们可以看出,不但array1
和array2
的内存地址发生改变,连array2
里面的Person
对象的内存地址也发生改变,生成了另外一个Person
对象。但person对象的name属性还没有确定深拷贝还是浅拷贝