通过copy方法可以创建可变对象或不可变对象的不可变副本,对于不可变副本,其对象的值不可以改变。

通过mutableCopy方法可以创建可变对象或不可变对象的可变副本,对于可变副本其对象是可变的。

复制分为浅复制和深复制两种:浅复制只是复制对象的引用,并没有复制对象的具体内容。深复制则创建了要复制对象的具体内容,并返回对象副本的引用。

对于复制Foundation中的对象,默认并不是深复制,例如copy NSMutableArray对象是浅复制,只是对其引用进行复制;而copy NSMutableString对象是深复制,对原来引用的对象的具体内容也进行了复制。

1.NSMutableArray和NSArray

首先创建1个数组(该数组中有3个对象)和4个数组指针:

  1. NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
  2. [NSMutableString stringWithString:@"1"],
  3. [NSMutableString stringWithString:@"2"],
  4. [NSMutableString stringWithFormat:@"3"],
  5. nil];
  6. NSMutableArray *marray2 = [marray1 mutableCopy];
  7. NSArray *array1 = [marray1 copy];
  8. NSArray *array2 = [marray1 mutableCopy];

(1)添加字符串到marray1[0]中:

  1. // append string to marray1[0]
  2. NSMutableString *mstr = marray1[0];
  3. [mstr appendString:@" append"];
  4. NSLog(@"append string to marray1[0]");
  5. NSLog(@"marray1 = %@", marray1);
  6. NSLog(@"marray2 = %@", marray2);
  7. NSLog(@"array1 = %@", array1);
  8. NSLog(@"array2 = %@", array2);
  1. 2014-01-31 21:10:39.097 Array[298:303] append string to marray1[0]
  2. 2014-01-31 21:10:39.098 Array[298:303] marray1 = (
  3. "1 append",
  4. 2,
  5. 3
  6. )
  7. 2014-01-31 21:10:39.098 Array[298:303] marray2 = (
  8. "1 append",
  9. 2,
  10. 3
  11. )
  12. 2014-01-31 21:10:39.098 Array[298:303] array1 = (
  13. "1 append",
  14. 2,
  15. 3
  16. )
  17. 2014-01-31 21:10:39.099 Array[298:303] array2 = (
  18. "1 append",
  19. 2,
  20. 3
  21. )

分析:

假设marray1中保存的是obj1,obj2,obj3组成的数组的首地址。将marray1复制给marray2,array1和array2,只是将指向数组第一个对象的内存地址复制到marray2等数组指针中保存。

在marray1[0]指向的对象obj1后面附加字符串append,由于marray1,marray2,array1和array2第一个指针指向的对象都是obj1,所以输出一致。

这里的copy方法和简单的赋值作用是一致的。

(2)为marray1[0]设置新的对象值:(注意(2)、(3)和(1)是相互独立的,下同)

  1. // set new object to marray1[0]
  2. marray1[0] = [NSMutableString stringWithString:@"new 1"];
  3. NSLog(@"set new object to marray1[0]");
  4. NSLog(@"marray1 = %@", marray1);
  5. NSLog(@"marray2 = %@", marray2);
  6. NSLog(@"array1 = %@", array1);
  7. NSLog(@"array2 = %@", array2);
  1. 2014-01-31 20:50:52.003 Array[4151:303] set new object to marray1[0]
  2. 2014-01-31 20:50:52.004 Array[4151:303] marray1 = (
  3. "new 1",
  4. 2,
  5. 3
  6. )
  7. 2014-01-31 20:50:52.005 Array[4151:303] marray2 = (
  8. 1,
  9. 2,
  10. 3
  11. )
  12. 2014-01-31 20:50:52.005 Array[4151:303] array1 = (
  13. 1,
  14. 2,
  15. 3
  16. )
  17. 2014-01-31 20:50:52.005 Array[4151:303] array2 = (
  18. 1,
  19. 2,
  20. 3
  21. )

分析:

这里创建了一个新的NSMutableString对象将其引用赋给marray1[0],而其他数组指针指向的对象不变,所以输出时其他数组不受影响。

(3)添加新的对象到marray1中:

  1. // add new object to marray1
  2. [marray1 addObject:[NSMutableString stringWithString:@"4"]];
  3. NSLog(@"add new object to marray1");
  4. NSLog(@"marray1 = %@", marray1);
  5. NSLog(@"marray2 = %@", marray2);
  6. NSLog(@"array1 = %@", array1);
  7. NSLog(@"array2 = %@", array2);
  1. 2014-01-31 20:51:46.867 Array[4167:303] add new object to marray1
  2. 2014-01-31 20:51:46.869 Array[4167:303] marray1 = (
  3. 1,
  4. 2,
  5. 3,
  6. 4
  7. )
  8. 2014-01-31 20:51:46.869 Array[4167:303] marray2 = (
  9. 1,
  10. 2,
  11. 3
  12. )
  13. 2014-01-31 20:51:46.869 Array[4167:303] array1 = (
  14. 1,
  15. 2,
  16. 3
  17. )
  18. 2014-01-31 20:51:46.869 Array[4167:303] array2 = (
  19. 1,
  20. 2,
  21. 3
  22. )

分析:

这里创建了一个新的可变字符串对象,并将其内存地址保存到指针marray1[3]中。而其他几个数组指针的引用不受影响。

(4)操作数组的引用

如果要单独替换marray1[0]指向的对象,应该先创建一个对象,然后再替换marray1[0]的引用。这样就不会对marray2[0]指向的对象造成影响。

  1. NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
  2. [NSMutableString stringWithString:@"1"],
  3. [NSMutableString stringWithString:@"2"],
  4. [NSMutableString stringWithFormat:@"3"],
  5. nil];
  6. NSMutableArray *marray2 = [marray1 mutableCopy];
  7. NSArray *array1 = [marray1 copy];
  8. NSArray *array2 = [marray1 mutableCopy];
  9. NSMutableString *mstr = [NSMutableString stringWithString:marray1[0]]; // 创建新的对象
  10. [mstr appendString:@" append"];
  11. [marray1 replaceObjectAtIndex:0 withObject:mstr]; // 替换marray1[0]的引用
  12.  
  13. NSLog(@"marray1 = %@", marray1);
  14. NSLog(@"marray2 = %@", marray2);
  15. NSLog(@"array1 = %@", array1);
  16. NSLog(@"array2 = %@", array2);

控制台输出:

  1. 2014-01-31 20:09:33.678 Dictionary[3735:303] marray1 = (
  2. "1 append",
  3. 2,
  4. 3
  5. )
  6. 2014-01-31 20:09:33.679 Dictionary[3735:303] marray2 = (
  7. 1,
  8. 2,
  9. 3
  10. )
  11. 2014-01-31 20:09:33.680 Dictionary[3735:303] array1 = (
  12. 1,
  13. 2,
  14. 3
  15. )
  16. 2014-01-31 20:09:33.680 Dictionary[3735:303] array2 = (
  17. 1,
  18. 2,
  19. 3
  20. )

再看一个例子:

  1. NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
  2. [NSMutableString stringWithString:@"1"],
  3. [NSMutableString stringWithString:@"2"],
  4. [NSMutableString stringWithFormat:@"3"],
  5. nil];
  6. NSMutableArray *marray2 = [marray1 mutableCopy];
  7. NSArray *array1 = [marray1 copy];
  8. NSArray *array2 = [marray1 mutableCopy];
  9.  
  10. [marray1 removeObjectAtIndex:0];
  11.  
  12. NSLog(@"marray1 = %@", marray1);
  13. NSLog(@"marray2 = %@", marray2);
  14. NSLog(@"array1 = %@", array1);
  15. NSLog(@"array2 = %@", array2);

控制台输出:

  1. 2014-01-31 20:10:40.716 Dictionary[3746:303] marray1 = (
  2. 2,
  3. 3
  4. )
  5. 2014-01-31 20:10:40.717 Dictionary[3746:303] marray2 = (
  6. 1,
  7. 2,
  8. 3
  9. )
  10. 2014-01-31 20:10:40.717 Dictionary[3746:303] array1 = (
  11. 1,
  12. 2,
  13. 3
  14. )
  15. 2014-01-31 20:10:40.718 Dictionary[3746:303] array2 = (
  16. 1,
  17. 2,
  18. 3
  19. )

尽管marray1,marray2,array1,array2指向同一个数组对象,但是[marray1 removeObjectAtIndex:0]移除的是marray1第一个元素,即移除的是对对象的引用,而不是移除数组中的第一个对象。所以不会影响到marray2  ,array1,array2 。

2.NSMutableString和NSString

复制NSMutableString对象测试代码如下:

  1. NSMutableString *mstr1 = [NSMutableString stringWithString:@"1"];
  2. NSMutableString *mstr2 = [mstr1 mutableCopy];
  3. NSString *str1 = [mstr1 copy];
  4. NSString *str2 = [mstr1 mutableCopy];
  5.  
  6. [mstr1 appendString:@" append"];
  7. NSLog(@"mstr1 = %@", mstr1);
  8. NSLog(@"mstr2 = %@", mstr2);
  9. NSLog(@"str1 = %@", str1);
  10. NSLog(@"str2 = %@", str2);
  1. 2014-01-31 20:54:20.423 String[4221:303] mstr1 = 1 append
  2. 2014-01-31 20:54:20.424 String[4221:303] mstr2 = 1
  3. 2014-01-31 20:54:20.424 String[4221:303] str1 = 1
  4. 2014-01-31 20:54:20.424 String[4221:303] str2 = 1

分析:

对mstr1指向的对象STRING1进行复制,这里复制的是对象  STRING1 本身的内容,也就是mstr2,str1,str2将分别指向对象  STRING2,STRING3,STRING4,对STRING1的修改(在后面附加字符串),将不会影响到其他几个引用指向的对象。

可见这里进行的是深复制。

注意不要改变copy后的对象的值,因为copy生成的对象是不可变的,强行修改会导致程序崩溃。

控制台输出为:

  1. 2014-02-01 00:57:24.903 Array[792:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'

3.NSMutableDictionary和NSDictionary

首先创建1个字典(字典中对应3个对象)和4个字典指针:

  1. NSMutableString *obj1 = [NSMutableString stringWithString:@"obj1"];
  2. NSMutableString *obj2 = [NSMutableString stringWithString:@"obj2"];
  3. NSMutableString *obj3 = [NSMutableString stringWithString:@"obj3"];
  4. NSMutableDictionary *mdic1 = [NSMutableDictionary dictionaryWithObjects:@[obj1, obj2, obj3]
  5. forKeys:@[@"key1", @"key2", @"key3"]];
  6. NSMutableDictionary *mdic2 = [mdic1 mutableCopy];
  7. NSDictionary *dic1 = [mdic1 copy];
  8. NSDictionary *dic2 = [mdic1 copy];

假设指针mdic1的索引key1,key2,key3分别对应对象obj1,obj2,obj3的内存地址。

对字典进行复制也是浅复制。

对mdic1复制,并赋值给mdic2,dic1,dic2,那么mdic2,dic1,dic2中指向的是同一个字典。

(1)添加字符串到mdic1的key1对应的可变字符串对象后:

  1. // append string to mdic1[@"key1"]
  2. NSMutableString *mstr = mdic1[@"key1"];
  3. [mstr appendString:@" append"];
  4. NSLog(@"append string to midc1[@\"key1\"]");
  5. NSLog(@"mdic1 = %@", mdic1);
  6. NSLog(@"mdic2 = %@", mdic2);
  7. NSLog(@"dic1 = %@", dic1);
  8. NSLog(@"dic2 = %@", dic2);
  1. 2014-01-31 22:07:29.241 Dictionary[431:303] append string to midc1[@"key1"]
  2. 2014-01-31 22:07:29.242 Dictionary[431:303] mdic1 = {
  3. key1 = "obj1 append";
  4. key2 = obj2;
  5. key3 = obj3;
  6. }
  7. 2014-01-31 22:07:29.243 Dictionary[431:303] mdic2 = {
  8. key1 = "obj1 append";
  9. key2 = obj2;
  10. key3 = obj3;
  11. }
  12. 2014-01-31 22:07:29.243 Dictionary[431:303] dic1 = {
  13. key1 = "obj1 append";
  14. key2 = obj2;
  15. key3 = obj3;
  16. }
  17. 2014-01-31 22:07:29.243 Dictionary[431:303] dic2 = {
  18. key1 = "obj1 append";
  19. key2 = obj2;
  20. key3 = obj3;
  21. }

上面代码中对key1对应的对象obj1进行修改(在对象后面附加字符串),由于mdic2等指向同一个字典,所以其输出将会和mdic1的输出一致。

(2)设置新的对象给key1:

  1. // set new object for key1
  2. NSMutableString *nobj1 = [NSMutableString stringWithString:@"new obj1"];
  3. [mdic1 setObject:nobj1 forKey:@"key1"];
  4. NSLog(@"set new object for key");
  5. NSLog(@"mdic1 = %@", mdic1);
  6. NSLog(@"mdic2 = %@", mdic2);
  7. NSLog(@"dic1 = %@", dic1);
  8. NSLog(@"dic2 = %@", dic2);
  1. 2014-01-31 22:08:01.617 Dictionary[448:303] set new object for key
  2. 2014-01-31 22:08:01.618 Dictionary[448:303] mdic1 = {
  3. key1 = "new obj1";
  4. key2 = obj2;
  5. key3 = obj3;
  6. }
  7. 2014-01-31 22:08:01.619 Dictionary[448:303] mdic2 = {
  8. key1 = obj1;
  9. key2 = obj2;
  10. key3 = obj3;
  11. }
  12. 2014-01-31 22:08:01.619 Dictionary[448:303] dic1 = {
  13. key1 = obj1;
  14. key2 = obj2;
  15. key3 = obj3;
  16. }
  17. 2014-01-31 22:08:01.619 Dictionary[448:303] dic2 = {
  18. key1 = obj1;
  19. key2 = obj2;
  20. key3 = obj3;
  21. }

这里只是修改了mdic1的索引key1中保存的内存地址,并不会对其他引用所指向的对象造成影响。

(3)在字典中添加新的key-value对:

  1. // add new key-value
  2. NSMutableString *obj4 = [NSMutableString stringWithString:@"obj4"];
  3. [mdic1 setObject:obj4 forKey:@"key4"];
  4. NSLog(@"add new key-value");
  5. NSLog(@"mdic1 = %@", mdic1);
  6. NSLog(@"mdic2 = %@", mdic2);
  7. NSLog(@"dic1 = %@", dic1);
  8. NSLog(@"dic2 = %@", dic2);
  1. 2014-01-31 22:12:14.678 Dictionary[466:303] add new key-value
  2. 2014-01-31 22:12:14.679 Dictionary[466:303] mdic1 = {
  3. key1 = obj1;
  4. key2 = obj2;
  5. key3 = obj3;
  6. key4 = obj4;
  7. }
  8. 2014-01-31 22:12:14.679 Dictionary[466:303] mdic2 = {
  9. key1 = obj1;
  10. key2 = obj2;
  11. key3 = obj3;
  12. }
  13. 2014-01-31 22:12:14.679 Dictionary[466:303] dic1 = {
  14. key1 = obj1;
  15. key2 = obj2;
  16. key3 = obj3;
  17. }
  18. 2014-01-31 22:12:14.680 Dictionary[466:303] dic2 = {
  19. key1 = obj1;
  20. key2 = obj2;
  21. key3 = obj3;
  22. }

现在为mdic1对应的字典添加新的key-value对,这不会影响到其他字典指针,所以输出不受影响。

小结:

1.浅复制复制的是对象的引用,对指针的修改并不会影响到指向的对象,更不会影响到其他指针。 深复制复制的是对象的内容,对对象的操作修改将影响到所有指向该对象的引用。

2.NSMutableArray和NSMutableDictionary的复制是浅复制,NSMutableString的复制是深复制。由于数组或字典中对象数目或大小可能非常大,所以对对象的复制可能引起大量开销,因此这里只复制引用可以节省开销。

复制对象 copy 与mutable copy的更多相关文章

  1. 复制对象(一)copy和mutableCopy方法

    本文转载至 http://www.tuicool.com/articles/Fn6rMn CSDN博客原文  http://blog.csdn.net/u010962810/article/detai ...

  2. Objective-C 谈谈深浅拷贝,copy和mutable copy都不是完全拷贝

    (一)字符串中的指针赋值,copy和mutablecopy NSString和NSString (1)指针赋值 肯定指向同一个字符串地址. (2)copy(和直接指向一样) NSString *str ...

  3. Python3标准库:copy复制对象

    1. copy复制对象 copy模块包括两个函数copy()和deepcopy(),用于复制现有的对象. 1.1 浅副本 copy()创建的浅副本(shallow copy)是一个新容器,其中填充了原 ...

  4. 条款12:复制对象时勿忘其每一个成分(Copy all parts of an object)

    NOTE: 1.Copying 函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 2.不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个 ...

  5. OC基础16:复制对象

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.浅复制即是指针赋值,复制对象的修改会影 ...

  6. copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)

    写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...

  7. Shallow copy and Deep copy

    Shallow copy and Deep copy 第一部分: 一.来自wikipidia的解释: Shallow copy One method of copying an object is t ...

  8. 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间

    [源码下载] 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间 作者:webabcd 介绍速战速决 之 PHP 动态地创 ...

  9. EC笔记:第二部分:12、复制对象时勿忘其每一个成分

    EC笔记:第二部分:12.复制对象时勿忘其每一个成分 1.场景 某些时候,我们不想使用编译器提供的默认拷贝函数(包括拷贝构造函数和赋值运算符),考虑以下类定义: 代码1: class Point{ p ...

随机推荐

  1. HDU 5671 矩阵

    Matrix Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Su ...

  2. codeforces 719C. Efim and Strange Grade

    C. Efim and Strange Grade time limit per test 1 second memory limit per test 256 megabytes input sta ...

  3. Kafka自我学习3-Scalable

    1.After created the zookeeper cluster, we found all broker cluster topic can be find in zoo1, zoo2, ...

  4. 入门级:GitHub和Git超超超详细使用教程!

    GitHub和Git入门 考虑到大家以前可能对版本控制工具和Linux命令行工具都不了解,我写了一个简单的博客来让大家学会入门使用方法. GitHub的简单使用 第一步 创建GitHub账号 1. 打 ...

  5. bzoj2442&&codevs4654 单调队列优化dp

    这道题也是一道单调队列 很明显满足各种性质 f[i]表示i不选前面k-1个都选的最小损失 维护的是个单增队列 q[head]是队列最小值 代码十分简介 注意longlong就okay #include ...

  6. HDU1267 下沙的沙子有几粒? 基础DP

    题目链接 题意:给定m个H和n个D(1<=n,m<=20),问这些字母构成的序列中,对于任意位置,从左开始数H的累积个数总是不比D的累计数少的排列有多少种. 题解:二维DP,画一个正方形, ...

  7. [bzoj1568][JSOI2008]Blue Mary开公司——李超线段树

    题目大意 题解 这道题需要用到一种叫做李超线段树的东西.我对于李超线段树,是这样理解的: 给节点打下的标记不进行下传,而是仅仅在需要的时候进行下传,这就是所谓永久化标记. 对于这道题,借用一张图, 这 ...

  8. 列出top中的pid

    #!/usr/bin/env python import os import string #方法1:通过字符串的isdigits来判断 #filelist = os.listdir('/proc') ...

  9. 美团网技术团队分享的MySQL索引及慢查询优化教程

    MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓“好马配好鞍”,如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位 ...

  10. 使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理【转】

    转自:https://www.qcloud.com/community/article/598765?fromSource=gwzcw.117333.117333.117333 这是<使用腾讯云 ...