理解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仍然可以实现应有的功能 ...
随机推荐
- 利用if else判断是否及格
static void Main(string[] args) { while (true) { string ...
- MS-DOS 7.10完整安装版(含图文安装程序)
大家知道,要想学习或使用DOS,安装一个DOS并进行实际操作是非常必要的.MS-DOS 7.10是一个非常好且强大实用的操作系统,而且兼容性和性能都十分强.要在系统中安装MS-DOS 7.10,可以使 ...
- [Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.1.1
Given any $k$-tupel of linearly independent vectors $X$ as above, there exists a $k$-tuple $Y$ biort ...
- diamond专题(三)—— diamond架构
大家好,这次为大家带来的是diamond的架构,架构如下图所示: 对该图进行一些说明: 1.作为一个配置中心,diamond的功能分为发布和订阅两部分.因为diamond存放的是持久数据,这些数据的变 ...
- nmon for linux
nmon(为Nigel's performance Monitor的简写) for linux工具是 IBM开源的在POWER, x86, x86_64, Mainframe & now AR ...
- FFT矩阵
举个例子: \[{F_4}=\left[{\begin{array}{*{20}{c}}1&1&1&1\\1&i&{-1}&{-i}\\1&{- ...
- 处理Google Play的相关方法
1.打开Google play软件的详细页面 Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.se ...
- 在iOS的XCode工程配置中为什么要用-all_load&-ObjC
-ObjC 这个flag告诉链接器把库中定义的Objective-C类和Category都加载进来.这样编译之后的app会变大(因为加载了其他的objc代码进来).但是如果静态库中有类和categor ...
- 问题-[Delphi]PixelFormat 图像颜色的数据格式
PixelFormat: (指定图像中每个像素的颜色数据的格式) Delphi 微软 ...
- A Tour of Go Type conversions
The expression T(v) converts the value v to the type T. Some numeric conversions: var i int = 42 var ...