说一下深拷贝和浅拷贝的基本概念: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的更多相关文章

  1. 理解Objective C 中id

    什么是id,与void *的区别 id在Objective C中是一个类型,一个complier所认可的Objective C类型,跟void *是不一样的,比如一个 id userName, 和vo ...

  2. 理解 Linux shell 中的一个方言:2>&1

    理解 Linux shell 中的一个方言:2>&1  2016-11-14 杜亦舒 前言 在使用 linux 命令或者 shell 编程时,这个用法常会遇到 2>&1 如 ...

  3. 浅谈Objective—C中的面向对象特性

    Objective-C世界中的面向对象程序设计 面向对象称程序设计可能是现在最常用的程序设计模式.如何开发实际的程序是存在两个派系的-- 面向对象语言--在过去的几十年中,很多的面向对象语言被发明出来 ...

  4. 【转】为什么我们都理解错了HTTP中GET与POST的区别

    GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...

  5. 【CSS3】 理解CSS3 transform中的Matrix(矩阵)

    理解CSS3 transform中的Matrix(矩阵) by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu ...

  6. 理解SQL Server中的权限体系(下)----安全对象和权限

    原文:http://www.cnblogs.com/CareySon/archive/2012/04/12/SQL-Security-SecurableAndPermission.html 在开始阅读 ...

  7. 【转载】理解C语言中的关键字extern

    原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...

  8. (转)理解SQL SERVER中的分区表

    简介 分区表是在SQL SERVER2005之后的版本引入的特性.这个特性允许把逻辑上的一个表在物理上分为很多部分.而对于SQL SERVER2005之前版本,所谓的分区表仅仅是分布式视图,也就是多个 ...

  9. Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming

    Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming 在Spark2.x中,Spark Streaming获得了比较全面的升级,称为St ...

  10. 理解SQL Server中索引的概念

    T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他   简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能 ...

随机推荐

  1. bzoj列表3

    水题列表 bzoj2429 裸的最小生成树 bzoj1567 二分答案+hash判断,判断序列.矩阵是否相同常用hash bzoj1087 简单的状压dp bzoj1754 高精度乘法,模拟竖式即可

  2. Win系统下制作U盘CLOVER引导+安装原版Mavericks10.9

    啃苹果有一段时间了,之前一直用白苹果,但是白苹果配置有所限制,对于我搞音频的人来讲,显得有点拖沓.所以研究了将近2年的黑苹果,最近心血来潮给大家一个比较傻瓜式的教程,首先强调一点,黑苹果是需要折腾的, ...

  3. App Store 加急审核方式

    https://developer.apple.com/contact/app-store/?topic=expedite 1:理由一般是用户安全问题或者崩溃问题成功率会高一些. 如果是崩溃问题,你最 ...

  4. .net文件压缩和解压及中文文件夹名称乱码问题

    /**************************注释区域内为引用http://www.cnblogs.com/zhaozhan/archive/2012/05/28/2520701.html的博 ...

  5. Selenium RC 环境搭建(eclipse)

    环境搭建参考:http://seleniumcn.cn/read.php?tid=7962  非常详细!晕乎晕乎了两天,看到这边帖子,终于搭起来了. 关于Selenium RC的原理,还是Seleni ...

  6. NOIP2001 数的划分

    题二 数的划分(20分) 问题描述 将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问 ...

  7. 集成电路中的assert和deassert应该如何翻译?

    转载自:http://m.blog.csdn.net/blog/code_robot/37663085 我每次看到电路中的assert与deassert时,总是感觉别扭,因为词典翻译总是"断 ...

  8. HDU4745 - Two Rabbits(区间DP)

    题目大意 给出一个长度为n的环状序列,两只兔子各自从一个点出发,一个顺时针跳,一个逆时针跳,每个时刻都要求两只兔子所在的数字是相同的,兔子最多跳一个圈~~~问兔子们最多能跳多少次 题解 一个逆时针跳, ...

  9. java-1-java开发环境安装及配置-绝对权威

    1,下载安装jdk1.8u45 http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html 一般安装目录 ...

  10. iOS中事件的传递和响应者链条

    在iOS 开发中,常见的事件有三种类型,分别是: (1)触摸事件:平常手指在屏幕上滑动,产生的事件都是触摸事件 (2)加速计事件:微信的摇一摇就是典型的加速计事件 (3)远程控制事件:耳机控制歌曲上一 ...