浅拷贝
浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。如:
char* str = (char*)malloc(100);
char* str2 = str;
|
iOS 里面的浅拷贝:
在 iOS 里面, 使用retain 关键字进行引用计数,就是一种更加保险的浅拷贝。他既让几个指针共用同一片内存空间,又可以在release 由于计数的存在,不会轻易的销毁内存,达到更加简单使用的目的。
深拷贝:
深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。
copy 与 retain 的区别:
copy 是创建一个新对象,retain 是创建一个指针,引用对象计数加一。 copy属性标识两个对象内容相同,新的对象retain count为1, 与旧有对象引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
iOS里的深拷贝:
这里指的是NSString, NSNumber等等一类的对象。
1
2
3
4
|
NSString *string = @”dddd";
NSString *stringCopy = [string copy];
NSMutableString *stringDCopy = [string mutableCopy];
[stringMCopy appendString:@
"!!"
];
通过内存发现
,string和stringCopy指向的是同一块内存区域(weak reference),引用计数没有发生改变。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,是两个独立的字符串内容是一样的。
|
拷贝构造:
当然在 ios 中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutableCopying协议的类才可以发送mutableCopy消息。
假如发送了一个没有遵守上诉两协议而发送copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。
如果是我们定义的对象,那么我们自己要实现NSCopying , NSMutableCopying这样就能调用copy和mutablecopy了。举个例子:
1
2
3
4
5
6
7
8
|
@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;
|
copy拷贝构造:
1
2
3
4
5
6
7
|
- (id)copyWithZone:(NSZone *)zone{
MyObj *copy = [[[self class] allocWithZone :zone] init];
copy->name = [_name copy];
copy->imutableStr = [_imutableStr copy];
copy->age = age;
return
copy;
}
|
mutableCopy拷贝构造:
1
2
3
4
5
6
|
- (id)mutableCopyWithZone:(NSZone *)zone{
MyObj *copy = NSCopyObject(self, 0, zone);
copy->name = [_name mutableCopy];
copy->age = age;
return
copy;
}
//+++++++++++++++++++++++++++++++++
iOS开发中,浅复制和深复制要更复杂一些,涉及到集合对象和非集合对象的copy与mutableCopy。 非集合对象:如NSString,NSInteger,NSNumber…… 集合对象:如NSArray,NSDictionary,…… 1:非集合对象的copy与mutableCopy。 非集合对象的copy与mutableCopy,只需要遵循以下规则即可: (1)可变对象的copy和mutableCopy方法都是深复制 (2)不可变对象的copy方法是浅复制,mutableCopy方法是深复制 (3)copy方法返回的对象是不可变对象 下面通过代码来验证: 可变对象的copy与 mutableCopy方法: //可变对象的复制,copy和mutableCopy都是深拷贝 NSMutableString *str1 = [NSMutableString stringWithString:@"test"]; NSMutableString *str2 = [str1 copy]; //copy返回的是不可变对象,因此str2不能改变,会发生崩溃 //[str2 appendString:@"test"]; NSMutableString *str3 = [str1 mutableCopy]; [str3 appendString:@"test"]; NSLog(@"%@ %@ %@",str1,str2,str3); NSLog(@"%p %p %p",str1,str2,str3); 执行结果: 可以看到,三个字符串的地址是不相同的,说明可变对象的copy和 mutableCopy方法都是深复制。 不可变对象的copy与mutableCopy方法: NSString *str1 = @"test";
//直接copy是浅复制
NSMutableString *str2 = [str1 copy];
//copy返回的是不可变对象,str2不能被修改,因此会发生崩溃
//[str2 appendString:@"test"];
//mutableCopy是深复制
NSMutableString *str3 = [str1 mutableCopy];
[str3 appendString:@"test"];
NSLog(@"%@ %@ %@",str1,str2,str3);
NSLog(@"%p %p %p",str1,str2,str3);
执行结果: 可以看到:前两个地址一样,第三个地址不一样,因此不可变对象的copy方法是浅复制,mutableCopy方法是深复制。 另外需要注意:无论是可变对象还是不可变对象,copy 方法返回的对象都是不可变的。mu tablecopy方法返回的对象是可变的; 2:集合对象的copy与mutableCopy 实际上,集合对象与非集合对象所遵循的规则基本上是一样的。 可变对象的的copy与mutableCopy 方法 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil]; //可变对象copy是深复制 NSMutableArray *array2 = [array1 copy]; //copy返回的是不可变对象,array2不能被修改,因此会崩溃 //[array2 addObject:@"d"]; //可变对象的mutableCopy是深复制 NSMutableArray *array3 = [array1 mutableCopy]; [array3 addObject:@"d"]; NSLog(@"%p %p %p",array1,array2,array3); 执行结果: 可以看到地址是不一样的。说明可变对象的copy和mutableCopy方法都是深复制。 不可变对象的copy与mutableCopy方法 NSArray *array1 = @[@"a",@"b",@"c"]; //不可变对象的copy方法,浅复制 NSArray *array2 = [array1 copy]; //不可变对象的mutableCopy方法,深复制 NSArray *array3 = [array1 mutableCopy]; NSLog(@"%p %p %p",array1,array2,array3); 执行结果: 可以看到,前两个地址一样,第三个地址不一样。说明不可变对象的copy方法是浅复制,mutableCopy方法是深复制。 集合对象和非集合对象的一个差别: 上面说的集合对象的深复制并不是严格意义上的深复制,而是单层深复制。 单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。比如说 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];调用copy方法 NSArray *array2 = [array1 copy] ,有分配了一块内存,array2指向了这块内存,但是数组内部的元素,
指向的仍然是数组1内部的元素,即内部元素是浅复制。
NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil]; //可变对象copy是深复制 NSMutableArray *array2 = [array1 copy]; //copy返回的是不可变对象,array2不能被修改,因此会崩溃 //[array2 addObject:@"d"]; //可变对象的mutableCopy是深复制 NSMutableArray *array3 = [array1 mutableCopy]; [array3 addObject:@"d"]; NSLog(@"%p %p %p",array1,array2,array3); NSLog(@"%p %p %p",array1[0],array2[0],array3[0]); 执行结果: 可以看到,三个数组的第一个元素的地址是一样的,也就是说内部元素是浅复制。 3:集合对象的完全复制 集合对象的完全复制,就是集合中的每一层的元素都是深复制。 方法一: 使用 [[NSArray alloc] initWithArray:array1 copyItems:YES]; 方法。 NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil]; NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES]; NSLog(@"%p %p",array1,array2); NSLog(@"%p %p",array1[0],array2[0]); 执行结果: 可以看到数组元素的地址不一样。 方法二: 先将集合进行归档,然后再解档。代码如下: NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil]; NSArray *array2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1 ] error:nil]; NSLog(@"%p %p",array1,array2); NSLog(@"%p %p",array1[0],array2[0]); 执行结果: 可以看到数组元素的地址不一样。
转载自:
|