复制对象(一)copy和mutableCopy方法
本文转载至 http://www.tuicool.com/articles/Fn6rMn
通过copy方法可以创建可变对象或不可变对象的不可变副本,对于不可变副本,其对象的值不可以改变。
通过mutableCopy方法可以创建可变对象或不可变对象的可变副本,对于可变副本其对象是可变的。
复制分为浅复制和深复制两种:浅复制只是复制对象的引用,并没有复制对象的具体内容。深复制则创建了要复制对象的具体内容,并返回对象副本的引用。
对于复制Foundation中的对象,默认并不是深复制,例如copy NSMutableArray对象是浅复制,只是对其引用进行复制;而copy NSMutableString对象是深复制,对原来引用的对象的具体内容也进行了复制。
1.NSMutableArray和NSArray
首先创建1个数组(该数组中有3个对象)和4个数组指针:
NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
[NSMutableString stringWithString:@"1"],
[NSMutableString stringWithString:@"2"],
[NSMutableString stringWithFormat:@"3"],
nil];
NSMutableArray *marray2 = [marray1 mutableCopy];
NSArray *array1 = [marray1 copy];
NSArray *array2 = [marray1 mutableCopy];
(1)添加字符串到marray1[0]中:
// append string to marray1[0]
NSMutableString *mstr = marray1[0];
[mstr appendString:@" append"];
NSLog(@"append string to marray1[0]");
NSLog(@"marray1 = %@", marray1);
NSLog(@"marray2 = %@", marray2);
NSLog(@"array1 = %@", array1);
NSLog(@"array2 = %@", array2);
2014-01-31 21:10:39.097 Array[298:303] append string to marray1[0]
2014-01-31 21:10:39.098 Array[298:303] marray1 = (
"1 append",
2,
3
)
2014-01-31 21:10:39.098 Array[298:303] marray2 = (
"1 append",
2,
3
)
2014-01-31 21:10:39.098 Array[298:303] array1 = (
"1 append",
2,
3
)
2014-01-31 21:10:39.099 Array[298:303] array2 = (
"1 append",
2,
3
)
分析:
假设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)是相互独立的,下同)
// set new object to marray1[0]
marray1[0] = [NSMutableString stringWithString:@"new 1"];
NSLog(@"set new object to marray1[0]");
NSLog(@"marray1 = %@", marray1);
NSLog(@"marray2 = %@", marray2);
NSLog(@"array1 = %@", array1);
NSLog(@"array2 = %@", array2);
2014-01-31 20:50:52.003 Array[4151:303] set new object to marray1[0]
2014-01-31 20:50:52.004 Array[4151:303] marray1 = (
"new 1",
2,
3
)
2014-01-31 20:50:52.005 Array[4151:303] marray2 = (
1,
2,
3
)
2014-01-31 20:50:52.005 Array[4151:303] array1 = (
1,
2,
3
)
2014-01-31 20:50:52.005 Array[4151:303] array2 = (
1,
2,
3
)
分析:
这里创建了一个新的NSMutableString对象将其引用赋给marray1[0],而其他数组指针指向的对象不变,所以输出时其他数组不受影响。
(3)添加新的对象到marray1中:
// add new object to marray1
[marray1 addObject:[NSMutableString stringWithString:@"4"]];
NSLog(@"add new object to marray1");
NSLog(@"marray1 = %@", marray1);
NSLog(@"marray2 = %@", marray2);
NSLog(@"array1 = %@", array1);
NSLog(@"array2 = %@", array2);
2014-01-31 20:51:46.867 Array[4167:303] add new object to marray1
2014-01-31 20:51:46.869 Array[4167:303] marray1 = (
1,
2,
3,
4
)
2014-01-31 20:51:46.869 Array[4167:303] marray2 = (
1,
2,
3
)
2014-01-31 20:51:46.869 Array[4167:303] array1 = (
1,
2,
3
)
2014-01-31 20:51:46.869 Array[4167:303] array2 = (
1,
2,
3
)
分析:
这里创建了一个新的可变字符串对象,并将其内存地址保存到指针marray1[3]中。而其他几个数组指针的引用不受影响。
(4)操作数组的引用
如果要单独替换marray1[0]指向的对象,应该先创建一个对象,然后再替换marray1[0]的引用。这样就不会对marray2[0]指向的对象造成影响。
NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
[NSMutableString stringWithString:@"1"],
[NSMutableString stringWithString:@"2"],
[NSMutableString stringWithFormat:@"3"],
nil];
NSMutableArray *marray2 = [marray1 mutableCopy];
NSArray *array1 = [marray1 copy];
NSArray *array2 = [marray1 mutableCopy];
NSMutableString *mstr = [NSMutableString stringWithString:marray1[0]]; // 创建新的对象
[mstr appendString:@" append"];
[marray1 replaceObjectAtIndex:0 withObject:mstr]; // 替换marray1[0]的引用 NSLog(@"marray1 = %@", marray1);
NSLog(@"marray2 = %@", marray2);
NSLog(@"array1 = %@", array1);
NSLog(@"array2 = %@", array2);
控制台输出:
2014-01-31 20:09:33.678 Dictionary[3735:303] marray1 = (
"1 append",
2,
3
)
2014-01-31 20:09:33.679 Dictionary[3735:303] marray2 = (
1,
2,
3
)
2014-01-31 20:09:33.680 Dictionary[3735:303] array1 = (
1,
2,
3
)
2014-01-31 20:09:33.680 Dictionary[3735:303] array2 = (
1,
2,
3
)
再看一个例子:
NSMutableArray *marray1 = [NSMutableArray arrayWithObjects:
[NSMutableString stringWithString:@"1"],
[NSMutableString stringWithString:@"2"],
[NSMutableString stringWithFormat:@"3"],
nil];
NSMutableArray *marray2 = [marray1 mutableCopy];
NSArray *array1 = [marray1 copy];
NSArray *array2 = [marray1 mutableCopy]; [marray1 removeObjectAtIndex:0]; NSLog(@"marray1 = %@", marray1);
NSLog(@"marray2 = %@", marray2);
NSLog(@"array1 = %@", array1);
NSLog(@"array2 = %@", array2);
控制台输出:
2014-01-31 20:10:40.716 Dictionary[3746:303] marray1 = (
2,
3
)
2014-01-31 20:10:40.717 Dictionary[3746:303] marray2 = (
1,
2,
3
)
2014-01-31 20:10:40.717 Dictionary[3746:303] array1 = (
1,
2,
3
)
2014-01-31 20:10:40.718 Dictionary[3746:303] array2 = (
1,
2,
3
)
尽管marray1,marray2,array1,array2指向同一个数组对象,但是[marray1 removeObjectAtIndex:0]移除的是marray1第一个元素,即移除的是对对象的引用,而不是移除数组中的第一个对象。所以不会影响到marray2 ,array1,array2 。
2.NSMutableString和NSString
复制NSMutableString对象测试代码如下:
NSMutableString *mstr1 = [NSMutableString stringWithString:@"1"];
NSMutableString *mstr2 = [mstr1 mutableCopy];
NSString *str1 = [mstr1 copy];
NSString *str2 = [mstr1 mutableCopy]; [mstr1 appendString:@" append"];
NSLog(@"mstr1 = %@", mstr1);
NSLog(@"mstr2 = %@", mstr2);
NSLog(@"str1 = %@", str1);
NSLog(@"str2 = %@", str2);
2014-01-31 20:54:20.423 String[4221:303] mstr1 = 1 append
2014-01-31 20:54:20.424 String[4221:303] mstr2 = 1
2014-01-31 20:54:20.424 String[4221:303] str1 = 1
2014-01-31 20:54:20.424 String[4221:303] str2 = 1
分析:
对mstr1指向的对象STRING1进行复制,这里复制的是对象 STRING1 本身的内容,也就是mstr2,str1,str2将分别指向对象 STRING2,STRING3,STRING4,对STRING1的修改(在后面附加字符串),将不会影响到其他几个引用指向的对象。
可见这里进行的是深复制。
注意不要改变copy后的对象的值,因为copy生成的对象是不可变的,强行修改会导致程序崩溃。

控制台输出为:
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个字典指针:
NSMutableString *obj1 = [NSMutableString stringWithString:@"obj1"];
NSMutableString *obj2 = [NSMutableString stringWithString:@"obj2"];
NSMutableString *obj3 = [NSMutableString stringWithString:@"obj3"];
NSMutableDictionary *mdic1 = [NSMutableDictionary dictionaryWithObjects:@[obj1, obj2, obj3]
forKeys:@[@"key1", @"key2", @"key3"]];
NSMutableDictionary *mdic2 = [mdic1 mutableCopy];
NSDictionary *dic1 = [mdic1 copy];
NSDictionary *dic2 = [mdic1 copy];
假设指针mdic1的索引key1,key2,key3分别对应对象obj1,obj2,obj3的内存地址。
对字典进行复制也是浅复制。
对mdic1复制,并赋值给mdic2,dic1,dic2,那么mdic2,dic1,dic2中指向的是同一个字典。
(1)添加字符串到mdic1的key1对应的可变字符串对象后:
// append string to mdic1[@"key1"]
NSMutableString *mstr = mdic1[@"key1"];
[mstr appendString:@" append"];
NSLog(@"append string to midc1[@\"key1\"]");
NSLog(@"mdic1 = %@", mdic1);
NSLog(@"mdic2 = %@", mdic2);
NSLog(@"dic1 = %@", dic1);
NSLog(@"dic2 = %@", dic2);
2014-01-31 22:07:29.241 Dictionary[431:303] append string to midc1[@"key1"]
2014-01-31 22:07:29.242 Dictionary[431:303] mdic1 = {
key1 = "obj1 append";
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] mdic2 = {
key1 = "obj1 append";
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] dic1 = {
key1 = "obj1 append";
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:07:29.243 Dictionary[431:303] dic2 = {
key1 = "obj1 append";
key2 = obj2;
key3 = obj3;
}
上面代码中对key1对应的对象obj1进行修改(在对象后面附加字符串),由于mdic2等指向同一个字典,所以其输出将会和mdic1的输出一致。
(2)设置新的对象给key1:
// set new object for key1
NSMutableString *nobj1 = [NSMutableString stringWithString:@"new obj1"];
[mdic1 setObject:nobj1 forKey:@"key1"];
NSLog(@"set new object for key");
NSLog(@"mdic1 = %@", mdic1);
NSLog(@"mdic2 = %@", mdic2);
NSLog(@"dic1 = %@", dic1);
NSLog(@"dic2 = %@", dic2);
2014-01-31 22:08:01.617 Dictionary[448:303] set new object for key
2014-01-31 22:08:01.618 Dictionary[448:303] mdic1 = {
key1 = "new obj1";
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] mdic2 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] dic1 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:08:01.619 Dictionary[448:303] dic2 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
这里只是修改了mdic1的索引key1中保存的内存地址,并不会对其他引用所指向的对象造成影响。
(3)在字典中添加新的key-value对:
// add new key-value
NSMutableString *obj4 = [NSMutableString stringWithString:@"obj4"];
[mdic1 setObject:obj4 forKey:@"key4"];
NSLog(@"add new key-value");
NSLog(@"mdic1 = %@", mdic1);
NSLog(@"mdic2 = %@", mdic2);
NSLog(@"dic1 = %@", dic1);
NSLog(@"dic2 = %@", dic2);
2014-01-31 22:12:14.678 Dictionary[466:303] add new key-value
2014-01-31 22:12:14.679 Dictionary[466:303] mdic1 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
key4 = obj4;
}
2014-01-31 22:12:14.679 Dictionary[466:303] mdic2 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:12:14.679 Dictionary[466:303] dic1 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
2014-01-31 22:12:14.680 Dictionary[466:303] dic2 = {
key1 = obj1;
key2 = obj2;
key3 = obj3;
}
现在为mdic1对应的字典添加新的key-value对,这不会影响到其他字典指针,所以输出不受影响。
小结:
1.浅复制复制的是对象的引用,对指针的修改并不会影响到指向的对象,更不会影响到其他指针。 深复制复制的是对象的内容,对对象的操作修改将影响到所有指向该对象的引用。
2.NSMutableArray和NSMutableDictionary的复制是浅复制,NSMutableString的复制是深复制。由于数组或字典中对象数目或大小可能非常大,所以对对象的复制可能引起大量开销,因此这里只复制引用可以节省开销。
复制对象(一)copy和mutableCopy方法的更多相关文章
- 关于:1.指针与对象;2.深浅拷贝(复制);3.可变与不可变对象;4.copy与mutableCopy的一些理解
最近对深浅拷贝(复制)做了一些研究,在此将自己的理解写下来,希望对大家有所帮助.本人尚处在摸索阶段,希望各位予以指正. 本文包括如下方向的探索: 1.指针与对象: 2.深/浅拷贝(复制): 3.可变/ ...
- JavaScript 复制对象【Object.assign方法无法实现深复制】
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...
- 探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法
NSString: //main.m #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { ...
- 对copy、mutableCopy理解
Objective - C 中有很多在日常项目中经常用到的常用代码,在这里着重的讲一下关于copy 和 mutableCopy 的区别以及相关用法. Objective - C 中可变对象和不可对象经 ...
- NSArray和NSMutableArray的copy和MutableCopy
NSArray: //main.m #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { ...
- 【转】copy 和 mutablecopy (深拷贝和浅拷贝)
阅读本文之前首先了解copy与retain的区别,如果有不正确的地方望大家多多指教: copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属 ...
- OC基础16:复制对象
"OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.浅复制即是指针赋值,复制对象的修改会影 ...
- copy和mutableCopy都是浅拷贝!!!------你被骗了很多年
所有系统容器类的copy或mutableCopy方法,都是浅拷贝!!! (ps:什么是容器?比如NSArray,NSMutableArray,NSDictionary,NSMutableDiction ...
- JavaScript 复制对象
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...
随机推荐
- 按照vue文档使用JavaScript钩子但是却不能执行动画?
大家刚入VUE肯定是先去阅读文档, 在 进入/离开 & 列表过渡 这一章节有一小节 --------- JavaScript钩子 详情见vue文档: https://cn.vuejs.or ...
- PHP+MYSQL的搭建
如今准备研究下微信的开发,所以要研究下PHP了,但对这个平台还是非常陌生的,所以网上找了些资料并測试,现贴出来给大家參考. 第一步:我们先下载[PHPStudy 2013]或者最新版本号: 下载地址: ...
- jbpm4(参数设置)
1.processDefinition.getDescription() <process name="task_test_2" xmlns="http://jbp ...
- Python学习笔记(七)函数的使用
python中的函数使用较简单,这里列出值得注意的几点: 内嵌函数 例如: # coding: utf-8 def foo(): def bar(): print 'bar() called. ...
- Unity3D研究院之脚本生成Android Google Project
一般安卓自动化打包直接会生成个APK出来,但是我不想生成APK,我想生成Eclipse项目. 然后在自动化完成后面的打包工作. 1 2 3 4 5 6 7 8 9 10 11 using Un ...
- EazyUI主页框架搭建纯JS样例
採用Jfinal+EazyUI 执行起来就好能够了 眼下还未增加后台代码 纯JS代码搭建的一个二级菜单+主页 客户换肤, 给使用EazyUI的新人一个高速可用的JS 搭建界面 也给自己保存下 界面 ...
- Python——标准库 Sys模块
---------------------------------------------------------------------------------------------------- ...
- Python——Socket 编程教程
这是用来快速学习 Python Socket 套接字编程的指南和教程.Python 的 Socket 编程跟 C 语言很像. Python 官方关于 Socket 的函数请看 http://docs. ...
- Vue工程模板文件 webpack打包
1.github github地址:https://github.com/MengFangui/VueProjectTemplate 2.webpack配置 (1)基础配置webpack.base.c ...
- CoolHash数据库引擎压测对比报告
Coolhash 当前性能指标:读写吞吐量超过百万,千万级别查询1秒完成,连续48小时打满CPU强压力运行稳定.redis官方公布读写性能在10万 tps,leveldb官方公布写性能在40万tps, ...