转载自:http://www.cnblogs.com/scorpiozj/archive/2011/01/25/1944496.html
这里主要侧重于集合类的深浅拷贝,主要事因为工作的时候遇到这个问题。
有不足的地方欢迎指正,转载请注明。
首先我们需要有这样的一个前提:
[array addObject:obj];
这样 obj 的引用计数会增加1,如果使用remove则obj的引用计数会减一。
ios对集合的内存处理就是这样的。
那么,假设 obj 只被 array 拥有:
id temp = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
如果你再要使用temp就会出错,因为这个时候 obj 已经被释放了。
(提醒一下,如果用 NSString 做测试,要注意 @“abc” 是常量 :-) )
由于在程序中经常会遇到集合类的传值,所以,简单的 retain 未必够用,需要对集合内容的拷贝,也就是深拷贝。
下面我们就来探讨一下。
Ios提供了copy和mutablecopy方法,顾名思义,copy就是复制了一个imutable的对象,而mutablecopy就是复制了一个mutable的对象。以下将举几个例子来说明。
1.系统的非容器类对象
这里指的是NSString,NSNumber等等一类的对象。
NSString*string =@"origion";
NSString*stringCopy = [stringcopy];
NSMutableString*stringMCopy = [stringmutableCopy];
[stringMCopyappendString:@"!!"];
查看内存可以发现,string和stringCopy指向的是同一块内存区域(又叫apple弱引用weak reference),此时stringCopy的引用计数和string的一样都为2。而stringMCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和string所指的一样。
再看下面的例子:
NSMutableString*string = [NSMutableStringstringWithString:@"origion"];
NSString*stringCopy = [stringcopy];
NSMutableString*mStringCopy = [stringcopy];
NSMutableString*stringMCopy = [stringmutableCopy];
[mStringCopyappendString:@"mm"];//error
[stringappendString:@" origion!"];
[stringMCopyappendString:@"!!"];
以上四个NSString对象所分配的内存都是不一样的。但是对于mStringCopy其实是个imutable对象,所以上述会报错。
对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
2.系统的容器类对象
指NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。
//copy返回不可变对象,mutablecopy返回可变对象
NSArray*array1 = [NSArrayarrayWithObjects:@"a",@"b",@"c",nil];
NSArray*arrayCopy1 = [array1copy];
//arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针
NSLog(@"array1 retain count: %d",[array1retainCount]);
NSLog(@"array1 retain count: %d",[arrayCopy1retainCount]);
NSMutableArray*mArrayCopy1 = [array1mutableCopy];
//mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的是同一个对象。mArrayCopy1还可以修改自己的对象
[mArrayCopy1addObject:@"de"];
[mArrayCopy1removeObjectAtIndex:0];
array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。
下面用另一个例子来测试一下。
NSArray*mArray1 = [NSArrayarrayWithObjects:[NSMutableStringstringWithString:@"a"],@"b",@"c",nil];
NSArray*mArrayCopy2 = [mArray1copy];
NSLog(@"mArray1 retain count: %d",[mArray1retainCount]);
NSMutableArray*mArrayMCopy1 = [mArray1mutableCopy];
NSLog(@"mArray1 retain count: %d",[mArray1retainCount]);
//mArrayCopy2,mArrayMCopy1和mArray1指向的都是不一样的对象,但是其中的元素都是一样的对象——同一个指针
//一下做测试
NSMutableString*testString = [mArray1objectAtIndex:0];
//testString = @"1a1";//这样会改变testString的指针,其实是将@“1a1”临时对象赋给了testString
[testStringappendString:@" tail"];//这样以上三个数组的首元素都被改变了
由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
NSArray*array = [NSArrayarrayWithObjects:[NSMutableStringstringWithString:@"first"],[NSStringstringWithString:@"b"],@"c",nil];
NSArray*deepCopyArray=[[NSArrayalloc]initWithArray: arraycopyItems:YES];
NSArray* trueDeepCopyArray = [NSKeyedUnarchiverunarchiveObjectWithData:
[NSKeyedArchiverarchivedDataWithRootObject: array]];
trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。举个例子,[[array objectAtIndex:0]appendstring:@”sd”]后其他的容器内对象并不会受影响。[[array objectAtIndex:1]和[[deepCopyArray
objectAtIndex:0]尽管是指向同一块内存,但是我们没有办法对其进行修改——因为它是不可改变的。所以指针复制已经足够。所以这并不是完全意义上的深拷贝,但是apple的官方文档将其列为deep copy了,并添加了copy和mutablity的关系说明,故在此做一说明(这边还有点疑惑,有了解的赐教啊)。
或者我们自己实现深拷贝的方法(略)。
3.自定义对象
如果是我们定义的对象,那么我们自己要实现NSCopying,NSMutableCopying这样就能调用copy和mutablecopy了。举个例子:
@interfaceMyObj : NSObject<NSCopying,NSMutableCopying>
{
NSMutableString*name;
NSString*imutableStr;
intage;
}
@property(nonatomic,retain) NSMutableString *name;
@property(nonatomic,retain) NSString *imutableStr;
@property(nonatomic)intage;
@end
@implementationMyObj
@synthesizename;
@synthesizeage;
@synthesizeimutableStr;
- (id)init
{
if(self= [superinit])
{
self.name= [[NSMutableStringalloc]init];
self.imutableStr= [[NSStringalloc]init];
age= -1;
}
returnself;
}
- (void)dealloc
{
[namerelease];
[imutableStrrelease];
[superdealloc];
}
- (id)copyWithZone:(NSZone*)zone
{
MyObj*copy = [[[selfclass]allocWithZone:zone]init];
copy->name= [namecopy];
copy->imutableStr= [imutableStrcopy];
//copy->name = [name copyWithZone:zone];;
//copy->imutableStr = [name copyWithZone:zone];//
copy->age=age;
returncopy;
}
- (id)mutableCopyWithZone:(NSZone*)zone
{
MyObj*copy =NSCopyObject(self,0, zone);
copy->name= [self.namemutableCopy];
copy->age=age;
returncopy;
}
@end
分享到:
相关推荐
关于IOS中深浅拷贝的例子,说不定有意想不到的结果
ios中深浅拷贝的讲解,通俗移动。深浅拷贝是ios开发人员面试经常会被问到的知识点,看了本文档,相信你回答ios中的深浅拷贝有不一样的认识。
一个ios的深浅拷贝的demo,请多多下载,多谢,多谢。
通过对不同类型的对象进行retain和copy进行深浅拷贝详细测试分析
swift5 Demo,Xcode11创建项目,并且支持iOS13以下版本,支持iOS13深浅模式图片以及颜色动态变化。 使用SnapKit 5.0约束框架,Alamofire 5.0最新版本网络请求。 项目为标准的UITabBarController布局,项目下载修改...
本文详细介绍了IOS中的三种拷贝方式,对iOS的深浅拷贝有疑问的朋友们可以参考下本文。
ios安全学习笔记, 供需要的人学习. 对iOS 感兴趣的同学可以看看
ios学习路线iOS学习路线ios学习路线iOS学习路线ios学习路线iOS学习路线
ios应用开发学习的好资料,很好的学习资料
51CTO下载-学习ios(必看经典)牛人40天精通iOS开发的学习方法 BecomeAnXcoder(SChinese) HowToCreateHelloWorldForiPhone iOS 6实践指南 iPhone应用程序编程指南 Learn Objective-C(zh)(v2) RoadMapiOSCh ...
ios obeject-c ios经典的学习资料
ios资料,学习资料,基础资料,
IOS新手入门学习资料集合. 包含“第一个IOS应用”、“iOS开发入门.doc”、“iOS学习笔记” 等学习资料的搜集。
《app-dev-curriculum-cn》 iOS playground文件 IOS 学习实战 swift
这是一套从一个对iOS开发感兴趣的学员到iOS...通过本系列课程的学习,希望使一个对iOS开发感兴趣,想从事iOS开发的学员,成为一名真正iOS开发人员,iOS从业者,iOS技术大牛,最重要的是学会解决开发中遇到困难的方法。
ios开发介绍:IOS开发入门学习路线介绍ios开发介绍:IOS开发入门学习路线介绍ios开发介绍:IOS开发入门学习路线介绍ios开发介绍:IOS开发入门学习路线介绍ios开发介绍:IOS开发入门学习路线介绍
非常全面的IOS课程学习体系,初学者有很好的指导作用
里面包含一些学习iOS的推荐网站和博客地址,以及一些书籍,可供iOS学习者查阅。