copy 与 retain 的区别:
1、copy 是创建一个新对象,retain 是创建一个指针,引用对象计数加一。
2、copy属性标识两个对象内容相同,新的对象retain count为1, 与旧有对象引用计数无关,旧有对象没有变化。
3、copy减少对象对上下文的依赖。
4、retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。
在实际开发的时候,发现,问题的本质确实是地址相同,就是浅拷贝,地址不同就是深拷贝。
浅拷贝
浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。浅拷贝只是对对象的简单拷贝,让几个对象共用一片内存,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,要不然会成为野指针。
iOS 里面的浅拷贝:
在 iOS 里面, 使用retain 关键字进行引用计数,就是一种更加保险的浅拷贝。他既让几个指针共用同一片内存空间,又可以在release 由于计数的存在,不会轻易的销毁内存,达到更加简单使用的目的。
深拷贝:
深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。
调用copy方法来拷贝不可变对象,或者调用mutableCopy方法拷贝可变对象时,
为新对象分配了内存空间,并且将对象数组中单个元素分别复制到新对象数组元素中。
对象默认为为浅复制,这种复制,仅仅是将引用从一个数组元素复制到另一个数组元素。
对,复制的是引用。所以,两个数组中的元素都指向内存中的同一个对象。
于是,这种情况就出现了,我们修改了原来数组中的对象,另一个数组中响应的元素也改变了。
iOS里的深拷贝:
iOS提供了copy和mutableCopy方法,顾名思义,copy就是复制了一个不可变的对象,而mutableCopy就是复制了一个可变的对象。
ios开发过程中,大体上会区分为对象和容器两个概念,对象的copy是浅拷贝,mutablecopy是深拷贝。容器也参照如上方法,但是需要记住,容器的包含对象的拷贝,无论使用copy,还是mutablecopy都将是浅拷贝。要想实现对象的深拷贝,必须自己提供拷贝的方法。
指的是NSString,NSNumber等对象。
NSString *string = @"origion"; NSString *stringCopy = [string copy]; NSMutableString *stringMCopy = [string mutableCopy]; [stringMCopy appendString:@"!!"];
查看内存可以发现,string和stringCopy指向的是同一块内存区域(又叫apple弱引用weak reference),此时stringCopy的引用计数和string的一样都为2(这里需要注意一下,因为@"origion"对象是常量数据段,不是堆上的对象,所以string与stringCopy实际都是指向一个非堆上的对象,他们的引用计数应该是-1,可以通过程序验证。我们所说的引用计数实际上是用于管理堆上申请的对象。)。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和string所指的一样。
看下面的例子:
NSMutableString *string = [NSMutableString stringWithString: @"origion"]; NSString *stringCopy = [string copy]; NSMutableString *mStringCopy = [string copy]; NSMutableString *stringMCopy = [string mutableCopy]; [mStringCopy appendString:@"mm"];//error [string appendString:@" origion!"];
以上四个NSString对象所分配的内存都是不一样的。但是对于mStringCopy其实是个imutable对象,所以上述会报错。对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
指NSArray,NSDictionary等。
//copy返回不可变对象,mutablecopy返回可变对象 NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSArray *arrayCopy1 = [array1 copy]; //arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针 NSLog(@"array1 retain count: %d",[array1 retainCount]); NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]); NSMutableArray *mArrayCopy1 = [array1 mutableCopy]; //mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的是同一个对象。mArrayCopy1还可以修改自己的对象 [mArrayCopy1 addObject:@"de"]; [mArrayCopy1 removeObjectAtIndex:0];
array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。
下面用另一个例子来测试一下:
NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray *mArrayCopy2 = [mArray1 copy]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy]; NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); //mArrayCopy2,mArrayMCopy1和mArray1指向的都是不一样的对象,但是其中的元素都是一样的对象——同一个指针
自定义类拷贝方法:
并不是说所有的对象都支持copy、和 mutablecopy方法,必须支持 NSCoding , NSMutableCopying协议,才可以。通常这个部分对于自定义对象而言,是要自行编写的。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法
@interface MyObj : NSObject<NSCopying,NSMutableCopying>
{
NSMutableString *name;
NSString *imutableStr;
int age;
}
@property (nonatomic, retain) NSMutableString *name;
@property (nonatomic, retain) NSString *imutableStr;
@property (nonatomic) int age;
@end
@implementation MyObj
@synthesize name;
@synthesize age;
@synthesize imutableStr;
- (id)init
{
if (self = [super init])
{
self.name = [[NSMutableString alloc]init];
self.imutableStr = [[NSString alloc]init];
age = -1;
}
return self;
}
- (void)dealloc
{
[name release];
[imutableStr release];
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
MyObj *copy = [[[self class] allocWithZone:zone] init];
copy->name = [name copy];
copy->imutableStr = [imutableStr copy];
// copy->name = [name copyWithZone:zone];
// copy->imutableStr = [name copyWithZone:zone]; copy->age = age;
return copy;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
MyObj *copy = NSCopyObject(self, 0, zone);
copy->name = [self.name mutableCopy];
copy->age = age;
return copy;
}
@end
浙公网安备 33010602011771号