一个Objective-C对象通常分配在堆上,并有一个或者多个指针指向它。如下代码及其关系图所示:

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = obj1; 

所谓浅拷贝与深拷贝,需要分为非容器类(如NSString)与容器类(如NSArray)来理解。如下表格所示:

与拷贝相关的两个系统函数是copy和mutableCopy,它们分别实现的是浅拷贝还是深拷贝呢?下面通过代码来验证:

不可变非容器:
NSString *str1 = @"this is a string.";
NSString *str2 = [str1 copy]; // 浅拷贝
NSString *str3 = [str1 mutableCopy]; // 深拷贝
NSLog(@"str1 address[%p] content[%@]", str1, str1);
NSLog(@"str2 address[%p] content[%@]", str2, str2);
NSLog(@"str3 address[%p] content[%@]", str3, str3); 输入:
str1 address[0x102fc8058] content[this is a string.]
str2 address[0x102fc8058] content[this is a string.]
str3 address[0x6040002500e0] content[this is a string.]
可变非容器:
NSMutableString *str4 = [[NSMutableString alloc] initWithString:@"this is a string."];
NSMutableString *str5 = [str4 copy]; // 深拷贝
NSMutableString *str6 = [str4 mutableCopy]; // 深拷贝
NSLog(@"str4 address[%p] content[%@]", str4, str4);
NSLog(@"str5 address[%p] content[%@]", str5, str5);
NSLog(@"str6 address[%p] content[%@]", str6, str6); 输出:
str4 address[0x60800024efd0] content[this is a string.]
str5 address[0x608000257dc0] content[this is a string.]
str6 address[0x608000257d90] content[this is a string.]
不可变容器:
NSArray *arr1 = @[[NSView new], [NSView new], [NSView new]];
NSArray *arr2 = [arr1 copy]; // 浅拷贝
NSArray *arr3 = [arr1 mutableCopy]; // 浅拷贝
NSLog(@"arr1 address[%p] content[%@]", arr1, arr1);
NSLog(@"arr2 address[%p] content[%@]", arr2, arr2);
NSLog(@"arr3 address[%p] content[%@]", arr3, arr3); 输出:
arr1 address[0x60800004f9c0] content[(
"<NSView: 0x6080001212c0>",
"<NSView: 0x608000121040>",
"<NSView: 0x6080001210e0>"
)]
arr2 address[0x60800004f9c0] content[(
"<NSView: 0x6080001212c0>",
"<NSView: 0x608000121040>",
"<NSView: 0x6080001210e0>"
)]
arr3 address[0x60800004c120] content[(
"<NSView: 0x6080001212c0>",
"<NSView: 0x608000121040>",
"<NSView: 0x6080001210e0>"
)]
可变容器:
NSMutableArray *arr4 = [[NSMutableArray alloc] initWithArray:@[[NSView new], [NSView new], [NSView new]] ];
NSMutableArray *arr5 = [arr4 copy]; // 浅拷贝
NSMutableArray *arr6 = [arr4 mutableCopy]; // 浅拷贝
NSLog(@"arr4 address[%p] content[%@]", arr4, arr4);
NSLog(@"arr5 address[%p] content[%@]", arr5, arr5);
NSLog(@"arr6 address[%p] content[%@]", arr6, arr6); 输出:
arr4 address[0x6000000599e0] content[(
"<NSView: 0x600000121a40>",
"<NSView: 0x600000121ae0>",
"<NSView: 0x600000121b80>"
)]
arr5 address[0x6000000599b0] content[(
"<NSView: 0x600000121a40>",
"<NSView: 0x600000121ae0>",
"<NSView: 0x600000121b80>"
)]
arr6 address[0x600000059980] content[(
"<NSView: 0x600000121a40>",
"<NSView: 0x600000121ae0>",
"<NSView: 0x600000121b80>"
)]

可以看到,无论是copy,还是mutableCopy,都不会拷贝容器中的对象。另外,懂C++的同学可能注意到,Objective-C的数组地址并不是数组首个元素的地址。

注意:可以不拘泥于浅拷贝和深拷贝的概念,理解其中的原理即可。

自定义的类,如果要使用copy方法,就要实现NSCopying协议中的方法:

- (id)copyWithZone:(NSZone*)zone; // zone参数没有用上,这是以前用来划分不同内存区的

类似,如果要使用mutableCopy方法,则要实现NSMutableCopying协议中的方法:

- (id)mutableCopyWithZone:(NSZone*)zone;

Objective-C 浅拷贝与深拷贝的更多相关文章

  1. [转] js对象浅拷贝和深拷贝详解

    本文为大家分享了JavaScript对象的浅拷贝和深拷贝代码,供大家参考,具体内容如下 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: var Chinese = ...

  2. 【转】Python中的赋值、浅拷贝、深拷贝介绍

    这篇文章主要介绍了Python中的赋值.浅拷贝.深拷贝介绍,Python中也分为简单赋值.浅拷贝.深拷贝这几种"拷贝"方式,需要的朋友可以参考下   和很多语言一样,Python中 ...

  3. 渐析java的浅拷贝和深拷贝

          首先来看看浅拷贝和深拷贝的定义:       浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝.       深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所 ...

  4. 关于JavaScript的浅拷贝和深拷贝

    在 JS 中有一些基本类型像是Number.String.Boolean,而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他 ...

  5. c#中浅拷贝和深拷贝的理解

    c#中拷贝有浅拷贝和深拷贝之分. 例如对象A,其中有值类型字段和引用类型字段: 1.浅拷贝: 对于值类型字段,直接逐位复制到新拷贝的副本对象中,修改副本的字段的值,不会影响源对象中字段的值: 对于引用 ...

  6. C#浅拷贝与深拷贝区别

    也许会有人这样解释C# 中浅拷贝与深拷贝区别: 浅拷贝是对引用类型拷贝地址,对值类型直接进行拷贝. 不能说它完全错误,但至少还不够严谨.比如:string 类型咋说? 其实,我们可以通过实践来寻找答案 ...

  7. IOS的浅拷贝和深拷贝

    什么是深拷贝和浅拷贝 浅拷贝:就是指针的复制,拷贝的指针跟原指针指向内存中的同一个位置的对象.至于对象的引用计数值是否+1,就是看拷贝的指针赋给给的变量是Strong类型的,还是week类型的. 如果 ...

  8. 关于python中赋值、浅拷贝、深拷贝之间区别的深入分析

    当重新学习了计算机基础课程<数据结构和算法分析>后再来看这篇自己以前写的博文,发现错误百出.python内置数据类型之所以会有这些特性,归根结底是它采用的是传递内存地址的方式,而不是传递真 ...

  9. js中的浅拷贝和深拷贝

    说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...

  10. 编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深 ...

随机推荐

  1. blfs(systemv版本)学习笔记-为桌面环境构建xorg服务

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs准备使用桌面环境,首先需要构建xorg服务 xorg服务项目地址:http://www.linuxfromscratch. ...

  2. 2018-01-15 Antlr4: 修改语法规则更接近普通BNF格式

    经 @沈默 在上文Antlr4添加中文变量赋求值,括号,各种问题评论中指出, 语法规则描述依赖于Antlr4生成的语法分析器的默认分析方法, 比如运算符的左联系, 以及优先级处理等等. 于是将语法修改 ...

  3. 2017-12-05 JavaScript实现ZLOGO子集: 前进+转向

    在前文中文编程语言之Z语言初尝试: ZLOGO 4与相关讨论后, 萌生了用JavaScript编写类似语言以便在线编程的想法. 于是使用 @TKT2016 (知乎账号)的ZLOGO语法设计, 在编程语 ...

  4. 使用fiddle处理跨域

    认真的用fiddle处理跨域 相信很多前端的同学都或多或少被跨域这个问题烦恼过,网上很多处理的方式其实都是要后端处理, 用fiddle来处理 ,就不必看后端的脸色了,自己安安心心的倒腾接口,何乐而不为 ...

  5. loadrunner 场景设计-设置结果文件保存路径

    场景设计-设置结果文件保存路径 by:授客 QQ:1033553122 Results->Results settings Results Name 结果文件夹名称 Directory 指定结果 ...

  6. Android View体系(五)从源码解析View的事件分发机制

    1.处理点击事件的方法 View的层级 我们知道View的结构是树形的结构,View可以放在ViewGroup中,这个ViewGroup也可以放到另一个ViewGroup中,这样层层的嵌套就组成了Vi ...

  7. 12.2、多线程通信:queue

    queue: 什么是队列:是一种特殊的结构,类似于列表.不过就像排队一样,队列中的元素一旦取出,那么就会从队列中删除. 线程之间的通信可以使用队列queue来进行 线程如何使用queue.Queue[ ...

  8. Scala学习笔记2 (带着问题学习, 逐渐扩展。理解吃透scala.)

    问题: 把 文本字符串"[1, 2, 3, 4, 5]" 转换成一个数组. 答案: val x = "[1, 2, 3, 4, 5]" val y =x sli ...

  9. vue.js的安装

    使用nodejs安装Vue-cli 1.安装完成node,node有自带的npm,可以直接在cmd中,找到nodeJs安装的路径下,进行命令行全局安装vue-cli.(npm install --gl ...

  10. Linux Mint Mate 常用

    Linux Mint基于Ubuntu  Mate 桌面版据说资源占用较少 http://mirrors.tuna.tsinghua.edu.cn/linuxmint-cd/stable/17.3/li ...