理解Objective-c中的copy
说一下深拷贝和浅拷贝的基本概念:a指针指向地址A1, 浅拷贝是创建了一个b指针指向地址A1;深拷贝是创建了一个c指针指向地址A2,A1和A2的地址不同。
我们看到NSObject接口里面是已经声明了copy和mutableCopy方法,也就是说任何的Objective-c的对象都可以调用这两个方法。
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
........
- (id)copy;
- (id)mutableCopy;
.......
@end
我们真的可以什么都不做就可以直接调用这两个方法吗?我们来做一个测试:
//test NSObject copy
NSObject *originObject = [[NSObject alloc] init];
NSObject *copiedObject = [originObject copy];
NSObject *mutableCopiedObject = [originObject mutableCopy];
NSLog(@"%@, %@, %@", originObject, copiedObject, mutableCopiedObject);
当代码执行到[originObject copy]时crash了,提示NSObject并没有实现NSCopying协议的方法,
-- ::56.680 NSLockTest[:] -[NSObject copyWithZone:]: unrecognized selector sent to instance 0x79f909b0
我们看看apple的解释:
Return Value
The object returned by the NSCopying protocol method copyWithZone:,. Discussion
This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is no implementation for copyWithZone:. NSObject does not itself support the NSCopying protocol. Subclasses must support the protocol and implement the copyWithZone: method. A subclass version of the copyWithZone: method should send the message to super first, to incorporate its implementation, unless the subclass descends directly from NSObject.
看出来了吧,copy和mutableCopy方法是给子类调用的,子类是要相应实现NSCopying和NSMutableCopy协议的。
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
有人会经常疑惑深拷贝和浅拷贝的问题,其实不需要有什么疑惑,如果是自定义的类,深拷贝还是浅拷贝是我们实现协议时自己控制的,比如
- (id)copyWithZone:(NSZone *)zone{
return [self deepCopy:zone];
}
- (id)shallowCopy:(NSZone *)zone{
return self;
}
- (id)deepCopy:(NSZone *)zone{
CopiedObject *copy = [[[self class] allocWithZone:zone] init];
copy.name = [self.name copyWithZone:zone];
return copy;
}
那只是对于系统实现NSCopying的类,我们可能不是很清楚到底是深拷贝还是浅拷贝,可以很简单的说,
- 对一个不可变对象,copy是浅拷贝;而mutableCopy则是对象深拷贝;
- 对可变对象复制,都是深拷贝,但copy返回的对象是不可变的
如果非要说一些特殊的话,对于容器类,通过copy操作后,并没有真正对容器内的各对象进行copy,容器内存储的指针和指针指向的每个对象都和拷贝前相同,如果想实现容器类中各对象的深拷贝有什么办法吗?
1)直接点的办法,不需要对容器内的对象做任何操作,把当前的容器写到本地(比如NSKeyedArchive, 文件存储)然后再重新从本地读取就可以实现深拷贝;
2)使用系统提供的方法,拿NSArray来举例,系统提供了这个方法:
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;
当flag为YES时,会NSArray中的每个对象发送copy消息,如果这个对象实现了NSCopy协议(显然如果这个对象没有实现NSCopying协议,就会crash),并且是深拷贝,新创建的这个数组就会是一个完全深拷贝的类(容器是新的,容器内的每个对象也是新的,对他们做任何修改都不会影响原来的容器)。
当flag为NO时,NSArray只会将原来存在数组里面的指针拿过来存一遍,不会对容器内的对象做任何的操作。当容器内的数据属性发生改变时,对应原容器内的数据属性也会跟着改变,因为他们就是一个对象。
最后补充两点:
1)copy和mutableCopy后的对象很明显的区别是,copy后是一个不可变的对象,mutbaleCopy后是可变的对象,copy前后可以拿NSdictionay和NSMutableDictionary、NSArray和NSMutableArray、NSString和NSMutbaleString等来对比。
2)copy和mutbaleCopy返回的对象在MRR中是需要我们手动release/autorelease的,因为要么是对原有的对象进行了retain操作,要么是重新创建了一个新的对象;换句话说,在实现协议的时候,我们并不需要对返回的对象发送autorelease消息。
参考资料:
1)https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Protocols/NSCopying_Protocol/
理解Objective-c中的copy的更多相关文章
- 理解Objective C 中id
什么是id,与void *的区别 id在Objective C中是一个类型,一个complier所认可的Objective C类型,跟void *是不一样的,比如一个 id userName, 和vo ...
- 理解 Linux shell 中的一个方言:2>&1
理解 Linux shell 中的一个方言:2>&1 2016-11-14 杜亦舒 前言 在使用 linux 命令或者 shell 编程时,这个用法常会遇到 2>&1 如 ...
- 浅谈Objective—C中的面向对象特性
Objective-C世界中的面向对象程序设计 面向对象称程序设计可能是现在最常用的程序设计模式.如何开发实际的程序是存在两个派系的-- 面向对象语言--在过去的几十年中,很多的面向对象语言被发明出来 ...
- 【转】为什么我们都理解错了HTTP中GET与POST的区别
GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...
- 【CSS3】 理解CSS3 transform中的Matrix(矩阵)
理解CSS3 transform中的Matrix(矩阵) by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu ...
- 理解SQL Server中的权限体系(下)----安全对象和权限
原文:http://www.cnblogs.com/CareySon/archive/2012/04/12/SQL-Security-SecurableAndPermission.html 在开始阅读 ...
- 【转载】理解C语言中的关键字extern
原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...
- (转)理解SQL SERVER中的分区表
简介 分区表是在SQL SERVER2005之后的版本引入的特性.这个特性允许把逻辑上的一个表在物理上分为很多部分.而对于SQL SERVER2005之前版本,所谓的分区表仅仅是分布式视图,也就是多个 ...
- Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming
Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming 在Spark2.x中,Spark Streaming获得了比较全面的升级,称为St ...
- 理解SQL Server中索引的概念
T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他 简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能 ...
随机推荐
- 【转】NI语法 JNI参考 JNI函数大全
原文网址:http://blog.sina.com.cn/s/blog_5de73d0b0101chk1.html 一.对照表 Java类型 本地类型 描述boolean ...
- 期待已久的2012年度最佳jQuery插件揭晓
近日,国外著名博客WDL发布了2012年度最佳 jQuery 插件.jQuery 自2006年发布以来,经过6年的迅速发展,目前已是最流行和使用最广泛的 JavaScript 框架,这主要归功于众多围 ...
- M-矩阵
实方阵 $A$ 称为 $M$-矩阵, 是指 $A=cI-B$, $B\geq 0$, $c\geq \rho(B)$. 这里, $M$ 据说是暗指 Minkowski.
- HDU5647 DZY Loves Connecting 树形DP
(先奉上jcvb大神的官方题解)BC 76 div 1 1002 对于每个结点i,统计出f[i]表示包含i的连通集有多少个,那么容易看出答案就是所有f[i]的和. 要计算f[i]是经典的树形DP问题. ...
- CodeBlocks+opencv2.4.4+cmake+MinGW
/*-----------------------------------------------------------------------------* * 版权声明:* 可以任意 ...
- Linux下安装启动nginx的过程
1.首先将nginx的安装包传到虚拟机里的/home目录下 2.为了方便nginx运行而不影响linux安全需创建组合用户 groupadd -r nginxuseradd -r -g nginx ...
- JDK1.5新特性(一)……Enhanced for Loop
援引 Enhanced for Loop - This new language construct eliminates the drudgery and error-proneness of it ...
- POJ 3450 Corporate Identity kmp+最长公共子串
枚举长度最短的字符串的所有子串,再与其他串匹配. #include<cstdio> #include<cstring> #include<algorithm> #i ...
- 如何从Windows Phone 生成PDF文档
我需要从我的Windows Phone应用程序生成PDF. 遗憾的是没有标准的免费的PDF生成库在Windows Phone上运行. 我不得不自己生成PDF,通过直接写入到文件格式. 这竟然是真的很容 ...
- Hive 0.12 Caused by: MetaException(message:Version information not found in metastore. )解决方法
配置完成Mysql存储元数据信息,启动后测试show tables报错ERROR exec.DDLTask: org.apache.hadoop.hive.ql.metadata.HiveExcept ...