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相当于两个对象指向同一个指针