OC 数组中的深拷贝与浅拷贝
浅拷贝:即指针拷贝,源对象和新对象指向的是同一个地址,也就是说浅拷贝要复出出来一个新的文件,但两个文件的地址还是一个。浅拷贝的话是只有不可变数组(如:NSArray,NSSet,NS字典)遇上copy,才是浅拷贝,剩下的都是深拷贝。
Dog * dog1 = [Dog new];
// 这里就是浅拷贝,即指针拷贝
Dog * dog2 = dog1;
深拷贝,自己定义的类一般需要遵循 NSCopying, NSMutableCopying 协议
Dog.h
@interface Dog : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic) NSInteger age;
@end
Dog.m
@implementation Dog
- (id)copyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (NSString *) description {
return [NSString stringWithFormat:@"dog age: %ld", self.age];
}
@end
main.m
Dog * dog1 = [Dog new];
dog1.age = 5;
NSLog(@"dog1: %p, %@", dog1, dog1);
// mutableCopy 返回的是可变对象,自然可以设置对象的属性值
Dog * dog2 = [dog1 mutableCopy];
dog2.age = 10;
// copy 返回的对象也可以设置对象的属性值
// 所以,从这里来看,其实自定义实现的 copy 和 mutableCopy 功能是一致的,都是返回可变对象的
Dog * dog2 = [dog1 copy];
dog2.age = 10;
NSLog(@"dog2: %p, %@", dog2, dog2);
OC 可变数组中的深拷贝与浅拷贝
所以,对数组进行深拷贝之后,其中对象的地址确实被重新创建。
NSMutableArray * arr1 = [NSMutableArray new];
for (int i = 0; i < 3; i++) {
Dog * dog = [Dog new];
[arr1 addObject:dog];
}
NSLog(@"arr1: %p, %@", arr1, arr1);
NSMutableArray * arr2 = [arr1 mutableCopy];
NSLog(@"arr2: %p, %@", arr2, arr2);
运行结果:
2017-010-10 10:55:39.895 深拷贝与浅拷贝[901:303] arr1: 0x1001089c0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
2017-10-10 10:55:39.917 深拷贝与浅拷贝[901:303] arr2: 0x100301ad0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
因为 “数组中只是存储了对象的地址,而非存储了对象的本体。”所以,Dog 对象的空间并没有被复制。
因此,可变数组的 “深拷贝”并没有将其中所有元素都复制,其中的对象元素只进行了浅复制!
解决方法:重新将所有对象都拷贝一份
NSMutableArray * arr2 = [NSMutableArray new];
for (int i = 0; i < arr1.count; i++) {
Dog * newDog = [arr1[i] copy];
[arr2 addObject:newDog];
}
NSLog(@"arr2: %p, %@", arr2, arr2);
OC中对于数组的深拷贝,不能想当然地认为,已经将其中元素空间都拷贝了。实际上,其中的元素只是浅拷贝而已!
如果需要实现深拷贝的话,可以通过一个一个元素进行深拷贝,重新添加到可变数组中!
COPY 返回一个不可变对象的副本,MutalbeCopy返回一个可变对象的副本。
NSArray *array=[NSArray arrayWithObjects:@"one",@"two", nil];
NSMutableArray *array1=[array copy];
[array1 addObject:@"three"]; //error
NSMutableArray *array2=[array mutableCopy];
[array2 addObject:@"three"]; //right
// insert code here...
NSLog(@"Hello, World!");
比较与区别
复制对象的基本概念:复制一个对象为副本,开辟一块新的内存来存储副本对象。
如果一个对象想具备复制的功能,必须实现协议和协议
NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableArray、NSMutableDictionay、NSMutableString,copy产生的对象时不可变的,mutableCopy产生的对象时可变的
COPY和MutableCopy的区别
COPY 返回一个不可变对象的副本,MutalbeCopy返回一个可变对象的副本。
浅copy和深copy
浅复制尽复制对象本身,对象里的属性、包含的对象不做复制。
浅复制只是复制指针,并没有创建新的内存空间。
深复制复制全部,包括对象的属性和其他对象
Foundation框架支持复制的类,默认是浅复制
对象的自定义拷贝
对象拥有复制特性,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法
深拷贝和浅拷贝的区别就在于copyWithZone方法的实现,
copy、mutableCopy和retain之间的关系
在Foundation对象中,copy是一个不可变的对象时,作用相当于retain
当使用mutableCopy时,不管源对象是否可变,副本是可变的,并且实现真正意义上的copy
当我们使用copy一个可变对象时,副本对象是不可变的。
NSFoundation,当我们copy的时一个不可变对象时,默认的copy都是浅拷贝,相当于retain
当使用mutableCopy时,不管对象是否可变,都会实现深拷贝
retain相当于两个对象指向同一个指针