关于IOS深浅拷贝的深入分析
2015-07-21 16:45
323 查看
看到的关于深浅拷贝的介绍,感觉讲的不错,就转载了一下,原文如下:
Apple官方文档如下:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
最近用Core Data做数据管理,Fetch到NSArray类型的结果数组,为了能够进行增、删、改,我把它MutableCopy到一个NSMutableArray数组中。增加、删除用manageModelsContext中的接口操作即可,修改则把NSArray结果中需要修改的实例取出来进行更改,然后用manageModelsContext保存即可完成修改到sqlite文件。
可是问题是我发现用MutableCopy得到的数组中取出的元素直接修改后保存,也能完成修改操作。于是就产生了这样的一个疑问:MutableCopy是浅拷贝??再下来我就发现copy相关的东西我还完全没有搞清楚。
首先关于copy和mutableCopy的行为:不管是NSString这种元素类、还是NSArray这样的容器类、还是Mutable和非Mutable类,copy和mutableCopy调用后表现的行为到底是什么样完成取决于类本身NSCopying和NSMutableCopying协议是如何实现的。
想要正常调用copy和mutableCopy两个函数,那么类就一定要实现对应的协议。
1. 元素数据的copy和mutableCopy。
常用的NSString类,示例代码如下:
[cpp]
view plaincopyprint?
NSString* string = @”a”;
NSString* stringCopy = [string copy];// stringCopy与string地址相同,retainCount+ 1
NSMutableString* stringMCopy = [string mutablecopy];// stringMCopy与string地址不同
NSMutableString* stringM1 = [stringMCopy copy];//地址与stringMCopy不同,且为不可修改
NSMutableString* stringM2 = [stringMCopy mutablecopy];//地址与stringMCopy不同,可修改
可以基本推出NSString和NSMutableString中两个协议的实现
[cpp]
view plaincopyprint?
NSString:
- (id)copywithZone:(NSZone*)zone
{
return self;
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
....
return copy;
}
NSMutableString:
- (id)copywithZone:(NSZone*)zone
{
NSString* copy = [[NSStringalloc] initxxxxxx];
....
return copy;//所以不可修改
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
....
return copy;
}
2. 容器类的copy和mutableCopy。
常用类NSArray和NSMutableArray,看如下示例代码:
[cpp]
view plaincopyprint?
Class1* obj1= ....;//正常初始化
NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil];
NSArray* arrayCopy = [array copy];//地址不变,retaincount+1
NSMutableArray* arrayMCopy = [array mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝
NSMutableArray* arrayM1 = [arrayMCopy Copy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝。arrayM1为NSArray不可修改
NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝
[cpp]
view plaincopyprint?
//推断
[cpp]
view plaincopyprint?
NSArray:
- (id)copywithZone:(NSZone*)zone
{
//伪码
return [self retain];
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
for (id element in self) {
[copy addObject:element];//element retian count + 1
....
}
return copy;
}
NSMutableArray:
- (id)copywithZone:(NSZone*)zone
{
NSArray* copy = [[NSArray alloc] initXXX];
/*把每个element加入到copy数组,retainCount+1*/
....
return copy;
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
for (id element in self) {
[copy addObject:element];//element retian count + 1
....
}
return copy;
}
3. 深拷贝
上面提到的官方文档中介绍两种实现深拷贝的方法:
a. 用Array的initWithArray: copyItems函数,如下:
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: someArraycopyItems: YES];
调用后,会对原NSArray中的每个元素调用其copy函数,并把返回的id加入到新的数组中。所以这是依赖于Obj对象类实现的深拷贝,如果- (id)copywithZone:(NSZone*)zone是重新分配一块内存赋值后返回,那么就是真正的深拷贝。如果直接返回自身,那么它只是浅拷贝。
b. 用archiver方式:
NSArray* trueDeepCopyArray = [NSKeyedUnarchiverunarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
这是真正意义上的深拷贝,不依赖于实际类Copying协议的实现。
4. 用Category实现自定义的深拷贝deepmutableCopy,如:
[cpp]
view plaincopyprint?
- (NSMutableArray *)mutableDeepCopy
{
NSMutableArray *ret = [[NSMutableArrayalloc] initWithCapacity:[self count]];
for (id value in self)
{
id oneCopy = nil;
if ([value respondsToSelector:@selector(mutableDeepCopy)])
oneCopy = [value mutableDeepCopy];
else if ([value respondsToSelector:@selector(mutableCopy)])
oneCopy = [value mutableCopy];
if (oneCopy == nil)
oneCopy = [value copy];
[ret addObject: oneCopy];
}
return ret;
}
看到的关于深浅拷贝的介绍,感觉讲的不错,就转载了一下,原文如下:
Apple官方文档如下:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
最近用Core Data做数据管理,Fetch到NSArray类型的结果数组,为了能够进行增、删、改,我把它MutableCopy到一个NSMutableArray数组中。增加、删除用manageModelsContext中的接口操作即可,修改则把NSArray结果中需要修改的实例取出来进行更改,然后用manageModelsContext保存即可完成修改到sqlite文件。
可是问题是我发现用MutableCopy得到的数组中取出的元素直接修改后保存,也能完成修改操作。于是就产生了这样的一个疑问:MutableCopy是浅拷贝??再下来我就发现copy相关的东西我还完全没有搞清楚。
首先关于copy和mutableCopy的行为:不管是NSString这种元素类、还是NSArray这样的容器类、还是Mutable和非Mutable类,copy和mutableCopy调用后表现的行为到底是什么样完成取决于类本身NSCopying和NSMutableCopying协议是如何实现的。
想要正常调用copy和mutableCopy两个函数,那么类就一定要实现对应的协议。
1. 元素数据的copy和mutableCopy。
常用的NSString类,示例代码如下:
[cpp]
view plaincopyprint?
NSString* string = @”a”;
NSString* stringCopy = [string copy];// stringCopy与string地址相同,retainCount+ 1
NSMutableString* stringMCopy = [string mutablecopy];// stringMCopy与string地址不同
NSMutableString* stringM1 = [stringMCopy copy];//地址与stringMCopy不同,且为不可修改
NSMutableString* stringM2 = [stringMCopy mutablecopy];//地址与stringMCopy不同,可修改
NSString* string = @”a”; NSString* stringCopy = [string copy];// stringCopy与string地址相同,retainCount+ 1 NSMutableString* stringMCopy = [string mutablecopy];// stringMCopy与string地址不同 NSMutableString* stringM1 = [stringMCopy copy];//地址与stringMCopy不同,且为不可修改 NSMutableString* stringM2 = [stringMCopy mutablecopy];//地址与stringMCopy不同,可修改
可以基本推出NSString和NSMutableString中两个协议的实现
[cpp]
view plaincopyprint?
NSString:
- (id)copywithZone:(NSZone*)zone
{
return self;
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
....
return copy;
}
NSMutableString:
- (id)copywithZone:(NSZone*)zone
{
NSString* copy = [[NSStringalloc] initxxxxxx];
....
return copy;//所以不可修改
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];
....
return copy;
}
NSString: - (id)copywithZone:(NSZone*)zone { return self; } - (id)mutableCopywithZone:(NSZone*)zone { NSMutableString* copy =[[NSMutableString alloc] initxxxxxx]; .... return copy; } NSMutableString: - (id)copywithZone:(NSZone*)zone { NSString* copy = [[NSStringalloc] initxxxxxx]; .... return copy;//所以不可修改 } - (id)mutableCopywithZone:(NSZone*)zone { NSMutableString* copy =[[NSMutableString alloc] initxxxxxx]; .... return copy; }
2. 容器类的copy和mutableCopy。
常用类NSArray和NSMutableArray,看如下示例代码:
[cpp]
view plaincopyprint?
Class1* obj1= ....;//正常初始化
NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil];
NSArray* arrayCopy = [array copy];//地址不变,retaincount+1
NSMutableArray* arrayMCopy = [array mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝
NSMutableArray* arrayM1 = [arrayMCopy Copy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝。arrayM1为NSArray不可修改
NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝
Class1* obj1= ....;//正常初始化 NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil]; NSArray* arrayCopy = [array copy];//地址不变,retaincount+1 NSMutableArray* arrayMCopy = [array mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝 NSMutableArray* arrayM1 = [arrayMCopy Copy];//地址改变,但是数组中成员指针 4000 和obj1相同,浅拷贝。arrayM1为NSArray不可修改 NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];//地址改变,但是数组中成员指针和obj1相同,浅拷贝
[cpp]
view plaincopyprint?
//推断
//推断
[cpp]
view plaincopyprint?
NSArray:
- (id)copywithZone:(NSZone*)zone
{
//伪码
return [self retain];
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
for (id element in self) {
[copy addObject:element];//element retian count + 1
....
}
return copy;
}
NSMutableArray:
- (id)copywithZone:(NSZone*)zone
{
NSArray* copy = [[NSArray alloc] initXXX];
/*把每个element加入到copy数组,retainCount+1*/
....
return copy;
}
- (id)mutableCopywithZone:(NSZone*)zone
{
NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];
for (id element in self) {
[copy addObject:element];//element retian count + 1
....
}
return copy;
}
NSArray: - (id)copywithZone:(NSZone*)zone { //伪码 return [self retain]; } - (id)mutableCopywithZone:(NSZone*)zone { NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx]; for (id element in self) { [copy addObject:element];//element retian count + 1 .... } return copy; } NSMutableArray: - (id)copywithZone:(NSZone*)zone { NSArray* copy = [[NSArray alloc] initXXX]; /*把每个element加入到copy数组,retainCount+1*/ .... return copy; } - (id)mutableCopywithZone:(NSZone*)zone { NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx]; for (id element in self) { [copy addObject:element];//element retian count + 1 .... } return copy; }
3. 深拷贝
上面提到的官方文档中介绍两种实现深拷贝的方法:
a. 用Array的initWithArray: copyItems函数,如下:
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: someArraycopyItems: YES];
调用后,会对原NSArray中的每个元素调用其copy函数,并把返回的id加入到新的数组中。所以这是依赖于Obj对象类实现的深拷贝,如果- (id)copywithZone:(NSZone*)zone是重新分配一块内存赋值后返回,那么就是真正的深拷贝。如果直接返回自身,那么它只是浅拷贝。
b. 用archiver方式:
NSArray* trueDeepCopyArray = [NSKeyedUnarchiverunarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
这是真正意义上的深拷贝,不依赖于实际类Copying协议的实现。
4. 用Category实现自定义的深拷贝deepmutableCopy,如:
[cpp]
view plaincopyprint?
- (NSMutableArray *)mutableDeepCopy
{
NSMutableArray *ret = [[NSMutableArrayalloc] initWithCapacity:[self count]];
for (id value in self)
{
id oneCopy = nil;
if ([value respondsToSelector:@selector(mutableDeepCopy)])
oneCopy = [value mutableDeepCopy];
else if ([value respondsToSelector:@selector(mutableCopy)])
oneCopy = [value mutableCopy];
if (oneCopy == nil)
oneCopy = [value copy];
[ret addObject: oneCopy];
}
return ret;
}
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- js判断客户端是iOS还是Android等移动终端的方法
- IOS开发环境windows化攻略
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- IOS 改变键盘颜色代码
- Android和IOS的浏览器中检测是否安装某个客户端的方法
- javascript实现阻止iOS APP中的链接打开Safari浏览器
- iOS开发之路--微博OAuth授权_取得用户授权的accessToken
- ios通过按钮点击异步加载图片
- ios中图像进行压缩方法汇总
- IOS检测指定路径的文件是否存在
- iOS、Mac OS X系统中编程实现汉字转拼音的方法(超级简单)