理解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仍然可以实现应有的功能 ...
随机推荐
- bzoj列表3
水题列表 bzoj2429 裸的最小生成树 bzoj1567 二分答案+hash判断,判断序列.矩阵是否相同常用hash bzoj1087 简单的状压dp bzoj1754 高精度乘法,模拟竖式即可
- Win系统下制作U盘CLOVER引导+安装原版Mavericks10.9
啃苹果有一段时间了,之前一直用白苹果,但是白苹果配置有所限制,对于我搞音频的人来讲,显得有点拖沓.所以研究了将近2年的黑苹果,最近心血来潮给大家一个比较傻瓜式的教程,首先强调一点,黑苹果是需要折腾的, ...
- App Store 加急审核方式
https://developer.apple.com/contact/app-store/?topic=expedite 1:理由一般是用户安全问题或者崩溃问题成功率会高一些. 如果是崩溃问题,你最 ...
- .net文件压缩和解压及中文文件夹名称乱码问题
/**************************注释区域内为引用http://www.cnblogs.com/zhaozhan/archive/2012/05/28/2520701.html的博 ...
- Selenium RC 环境搭建(eclipse)
环境搭建参考:http://seleniumcn.cn/read.php?tid=7962 非常详细!晕乎晕乎了两天,看到这边帖子,终于搭起来了. 关于Selenium RC的原理,还是Seleni ...
- NOIP2001 数的划分
题二 数的划分(20分) 问题描述 将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问 ...
- 集成电路中的assert和deassert应该如何翻译?
转载自:http://m.blog.csdn.net/blog/code_robot/37663085 我每次看到电路中的assert与deassert时,总是感觉别扭,因为词典翻译总是"断 ...
- HDU4745 - Two Rabbits(区间DP)
题目大意 给出一个长度为n的环状序列,两只兔子各自从一个点出发,一个顺时针跳,一个逆时针跳,每个时刻都要求两只兔子所在的数字是相同的,兔子最多跳一个圈~~~问兔子们最多能跳多少次 题解 一个逆时针跳, ...
- java-1-java开发环境安装及配置-绝对权威
1,下载安装jdk1.8u45 http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html 一般安装目录 ...
- iOS中事件的传递和响应者链条
在iOS 开发中,常见的事件有三种类型,分别是: (1)触摸事件:平常手指在屏幕上滑动,产生的事件都是触摸事件 (2)加速计事件:微信的摇一摇就是典型的加速计事件 (3)远程控制事件:耳机控制歌曲上一 ...