NSArray和NSMutableArray的copy和MutableCopy
NSArray:
//main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//这里为不可变数组赋值以可变字符串对象,稍后会作说明,此测试换成NSString也可。
NSArray *array1 = [[NSArray alloc]initWithObjects:
[NSMutableString stringWithString:@"a"],
[NSMutableString stringWithString:@"b"],
[NSMutableString stringWithString:@"c"],
[NSMutableString stringWithString:@"d"], nil];
NSArray *array2;
NSArray *array3;
NSArray *array4;
array2 = array1;
array3 = [array1 copy];
array4 = [array1 mutableCopy];
NSLog(@"array1 address = %p", array1); //输出array1指向的地址
NSLog(@" ");
NSLog(@"array2 address = %p", array2); //输出array2指向的地址
NSLog(@" ");
NSLog(@"array3 address = %p", array3); //输出array3指向的地址
NSLog(@" ");
NSLog(@"array4 address = %p", array4); //输出array4指向的地址
}
return ;
}
//运行结果: -- ::55.919 copyTest2[:] array1 address = 0x1001025b0
-- ::55.920 copyTest2[:]
-- ::55.920 copyTest2[:] array2 address = 0x1001025b0
-- ::55.920 copyTest2[:]
-- ::55.920 copyTest2[:] array3 address = 0x1001025b0
-- ::55.920 copyTest2[:]
-- ::55.920 copyTest2[:] array4 address = 0x100102d20
Program ended with exit code:
结果分析:
(1)array1,array2,array3都指向了相同的地址。array1的copy方法没有分配到新的内存地址,而MutableCopy方法却分配了新的内存。这与NSString的copy和MutableCopy方法得到的结果是一样的。详情参考我的另一篇文章:探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法。
(2)理论上来说,array1在数组的层面上进行修改,会使得array2和array3跟着改变。
这里有很重要的附加说明:
①array1是不可变数组,所以我在前一句说在数组的层面上修改的时候,会说理论上,它实际上在数组的层面是不可以被修改的。
②但这不意味着它不能被改变。我上面以可变字符串对其进行元素填充是有用意的,因为确实可以array1在数组元素的层面进行修改,而不是在数组的层面上修改。具体做法是再定义一个可变字符串NSMutableString *mStr = array1[0],然后使用语句 [mStr appendString:@"AAAAA"]; 会导致array1[0]的值也会跟着变化。
他们之间的地址引用关系如图1所示:

图1
NSMutableArray:
//main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSMutableArray *array1 = [[NSMutableArray alloc]initWithObjects:
[NSMutableString stringWithString:@"a"],
[NSMutableString stringWithString:@"b"],
[NSMutableString stringWithString:@"c"],
[NSMutableString stringWithString:@"d"], nil];
NSMutableArray *array2;
NSMutableArray *array3;
NSMutableArray *array4;
NSMutableString *mStr = array1[]; //定义一个可变字符串,用于在数组元素层面上修改数组元素
NSLog(@"Before array1 changes:");
array2 = array1;
array3 = [array1 copy];
array4 = [array1 mutableCopy];
NSLog(@"array1 address is %p", array1); //array1指向的地址
NSLog(@"\narray1:%@", array1); //array1原始内容
NSLog(@"array2 address is %p", array2); //array2指向的地址
NSLog(@"\narray2:%@", array2); //array2原始内容
NSLog(@"array3 address is %p", array3); //array3指向的地址
NSLog(@"\narray3:%@", array3); //array3原始内容
NSLog(@"array4 address is %p", array4); //array4指向的地址
NSLog(@"\narray4:%@", array4); //array4原始内容
[array1 insertObject:@ atIndex:]; //array1在数组的层面上修改
NSLog(@" ");
NSLog(@"After the first changes of array1:");
NSLog(@"array1 address is %p", array1); //第一次修改后array1指向的地址
NSLog(@"\narray1:%@", array1); //第一次修改后array1的数据
NSLog(@"array2 address is %p", array2); //第一次修改后array2指向的地址
NSLog(@"\narray2:%@", array2); //第一次修改后array2的数据
NSLog(@"array3 address is %p", array3); //第一次修改后array3指向的地址
NSLog(@"\narray3:%@", array3); //第一次修改后array3的数据
NSLog(@"array4 address is %p", array4); //第一次修改后array4指向的地址
NSLog(@"\narray4:%@", array4); //第一次修改后array4的数据
[mStr appendString:@"AAAAAAAAAAAA"]; //在数组元素的层面上修改
NSLog(@" ");
NSLog(@"After the second changes of array1:");
NSLog(@"array1 address is %p", array1); //第二次修改后array1指向的地址
NSLog(@"\narray1:%@", array1); //第二次修改后array1的数据
NSLog(@"array2 address is %p", array2); //第二次修改后array2指向的地址
NSLog(@"\narray2:%@", array2); //第二次修改后array2的数据
NSLog(@"array3 address is %p", array3); //第二次修改后array3指向的地址
NSLog(@"\narray3:%@", array3); //第二次修改后array3的数据
NSLog(@"array3 address is %p", array3); //第二次修改后array3指向的地址
NSLog(@"\narray3:%@", array3); //第二次修改后array3的数据
NSLog(@"array4 address is %p", array4); //第二次修改后array4指向的地址
NSLog(@"\narray4:%@", array4); //第二次修改后array4的数据
}
return ;
}
//运行结果 -- ::46.511 copyTest2[:] Before array1 changes:
-- ::46.512 copyTest2[:] array1 address is 0x100108160
-- ::46.512 copyTest2[:]
array1:(
a,
b,
c,
d
)
-- ::46.512 copyTest2[:] array2 address is 0x100108160
-- ::46.512 copyTest2[:]
array2:(
a,
b,
c,
d
)
-- ::46.512 copyTest2[:] array3 address is 0x103101050
-- ::46.512 copyTest2[:]
array3:(
a,
b,
c,
d
)
-- ::46.512 copyTest2[:] array4 address is 0x103101080
-- ::46.512 copyTest2[:]
array4:(
a,
b,
c,
d
)
-- ::46.512 copyTest2[:]
-- ::46.512 copyTest2[:] After the first changes of array1:
-- ::46.512 copyTest2[:] array1 address is 0x100108160
-- ::46.512 copyTest2[:]
array1:(
a,
b,
,
c,
d
)
-- ::46.512 copyTest2[:] array2 address is 0x100108160
-- ::46.513 copyTest2[:]
array2:(
a,
b,
,
c,
d
)
-- ::46.513 copyTest2[:] array3 address is 0x103101050
-- ::46.513 copyTest2[:]
array3:(
a,
b,
c,
d
)
-- ::46.513 copyTest2[:] array4 address is 0x103101080
-- ::46.513 copyTest2[:]
array4:(
a,
b,
c,
d
)
-- ::46.513 copyTest2[:]
-- ::46.513 copyTest2[:] After the second changes of array1:
-- ::46.513 copyTest2[:] array1 address is 0x100108160
-- ::46.513 copyTest2[:]
array1:(
aAAAAAAAAAAAA,
b,
,
c,
d
)
-- ::46.513 copyTest2[:] array2 address is 0x100108160
-- ::46.513 copyTest2[:]
array2:(
aAAAAAAAAAAAA,
b,
,
c,
d
)
-- ::46.513 copyTest2[:] array3 address is 0x103101050
-- ::46.513 copyTest2[:]
array3:(
aAAAAAAAAAAAA,
b,
c,
d
)
-- ::46.513 copyTest2[:] array3 address is 0x103101050
-- ::46.513 copyTest2[:]
array3:(
aAAAAAAAAAAAA,
b,
c,
d
)
-- ::46.514 copyTest2[:] array4 address is 0x103101080
-- ::46.514 copyTest2[:]
array4:(
aAAAAAAAAAAAA,
b,
c,
d
)
Program ended with exit code:
这次先上图:

图2(改变前)

图3(第一次改变后)

图4(第二次改变后)
结果分析:
(1)根据图2、图3和图4,结论是显而易见的。NSMutableArray响应Copy方法不同于NSArray的Copy方法,前者响应Copy方法会再分配新的内存给Copy的新副本,后者却不会(因此,可以说Copy对NSArray来说执行的是浅复制,对NSMutableArray来说执行的是深复制,关于深浅复制的理解,可以看这个链接下的回答 https://baike.1688.com/doc/view-d36106768.html,但是NSMutableArray响应Copy或者MutableCopy方法执行的这种深复制也并“不彻底”,在我们下面会讨论到的归档,将会看到一种更为彻底的深复制);相同的是两者的MutableCopy都能分配新的内存给新副本。所以两个可变数组array3、array4都指向了新的地址,与array1不同,因此对array1响应的 insertObject:atIndex: 方法array3和array4都不会受到影响。
(2)同时,我们在这一次实验结果中可以看到在数组元素层面上修改数组元素。
使用归档程序复制MutableArray对象:
//main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSData *data;
NSMutableArray *dataArray = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"one"],[NSMutableString stringWithString:@"two"],[NSMutableString stringWithString:@"three"], nil];
NSMutableArray *dataArray2 ;
NSMutableString *mStr;
//使用归档器进行深复制
data = [NSKeyedArchiver archivedDataWithRootObject:dataArray];
dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
mStr = dataArray2[];
[mStr appendString:@"ONE"];
NSLog(@"dataArray:");
for(NSString *elem in dataArray)
{
NSLog(@"%@", elem);
}
NSLog(@"\ndataArray2:");
for(NSString *elem in dataArray2)
{
NSLog(@"%@", elem);
}
//查看dataArray和dataArray2两个可变数组的地址
NSLog(@"\n");
NSLog(@"%p", dataArray);
NSLog(@"%p", dataArray2);
//查看dataArray和dataArray2两个可变数组首个元素的地址
NSLog(@"\n");
NSLog(@"%p", dataArray[]);
NSLog(@"%p", dataArray2[]);
}
return ;
}
//运行结果: -- ::13.426 Objective-C-p450[:] dataArray:
-- ::13.427 Objective-C-p450[:] one
-- ::13.427 Objective-C-p450[:] two
-- ::13.427 Objective-C-p450[:] three
-- ::13.427 Objective-C-p450[:]
-- ::13.427 Objective-C-p450[:] dataArray2:
-- ::13.427 Objective-C-p450[:] oneONE
-- ::13.427 Objective-C-p450[:] two
-- ::13.427 Objective-C-p450[:] three
-- ::13.427 Objective-C-p450[:]
-- ::13.427 Objective-C-p450[:] 0x1007005e0
-- ::13.427 Objective-C-p450[:] 0x100703850
-- ::13.427 Objective-C-p450[:]
-- ::13.428 Objective-C-p450[:] 0x100700250
-- ::13.428 Objective-C-p450[:] 0x100702720
Program ended with exit code:

图5(使用归档执行深复制)
结果分析:
(1)通过图5与图4的对比可以发现,图5不但给数组分配了空间,同时给数组元素的引用对象也分配了空间,即在原来只有@
"one",@"two",@"three" 3个字符串的情况下,又新分配了三个空间存储新的3个字符串@"one",@"two",@"three"。图4中MutableArray响应的无论是Copy方法还是MutableCopy方法都仅仅是给数组分配了新空间,而它们数组元素引用的都是堆中唯一一份字符串@""
(2)dataArray和dataArray2的数组元素不再是引用同一个对象了,因此使用mStr试图去改变dataArray2[0],并不影响dataArray[0]。我们在最后输出了dataArray和dataArray2,以及dataArray[0]和dataArray2[0],更清晰地看到它们的地址完全不同。
NSArray和NSMutableArray的copy和MutableCopy的更多相关文章
- --NSArray与NSMutableArray用copy修饰还是strong(转)
一.NSMutableArray 被copy.strong修饰后的变化: 把NSMutableArray用copy修饰有时就会crash,因为对这个数组进行了增删改操作,而copy后的数组变成了不可变 ...
- iOS之NSArray类簇简介-(copy、mutableCopy导致程序crash)
1.前言 开发时常常用数组对数据进行处理,对NSMutableArray进行操作时经常导致程序崩溃,特研究一下NSArray的类簇!涉及__NSPlaceholderArray.__NSArray0. ...
- Objective-C中的Strong、Copy与MutableCopy
面试过程中经常被问到ARC中Strong.Copy的区别是什么.普通的回答是:一样.文艺(正确)的回答是:分情况(我擦!WQY#$&Y**%OWEUR) 可以先参考这篇文章http://www ...
- 对copy、mutableCopy理解
Objective - C 中有很多在日常项目中经常用到的常用代码,在这里着重的讲一下关于copy 和 mutableCopy 的区别以及相关用法. Objective - C 中可变对象和不可对象经 ...
- 集合使用copy与mutableCopy的区别
集合(NSArray,NSSet,NSDictionary等)使用copy与mutableCopy的区别是类似的,下面以NSMutableArray.NSArray 为例子验证如下: NSMutabl ...
- iOS Copy 和 MutableCopy的区别 深浅拷贝的区别-供参考
概述 对于系统的非容器类对象,对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝).如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的. 对于 ...
- 【转】copy 和 mutablecopy (深拷贝和浅拷贝)
阅读本文之前首先了解copy与retain的区别,如果有不正确的地方望大家多多指教: copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属 ...
- copy和mutableCopy的深、浅拷贝
对象拷贝主要由两种方式:copy和mutableCopy.浅拷贝是指直接将指针指向原有的地址,从而达到复制的目的.深拷贝是指重新生成一个对象,将原有对象的内容复制到新的对象中.copy 返回的是一个不 ...
- NSArray 与 NSMutableArray 的排序
由于集合的使用过程中,经常需要对数组进行排序操作,此博客用于总结对在OC中对数组排序的几种方法 1.当数组中存放的是Foundation框架中提供的对象时,直接使用 compare:方法 如:NSSt ...
随机推荐
- JSP Ajax
html代码: <!DOCTYPE html> <html> <script> function display() { var div=document.getE ...
- php 导出excel表格
方式一:使用PHPExcel类库 //引入PHPExcel库文件(路径根据自己情况)include './phpexcel/Classes/PHPExcel.php'; $excel = new PH ...
- OpenSessionInViewFilter与org.springframework.dao.InvalidDataAccessApiUsageException
报错:org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in r ...
- python 魔法方法
I am not a creator, I just a porter. Note: Everything is object in python. 对于Python来说一切都是对象,也就是函数的参数 ...
- C语言小结之结构类型
C语言小结之结构类型 @刁钻的游戏 (1)枚举型类型enum COLOR {BLACK,RED,BLUE};//声明一种新的数据类型,其值分别为0,1,2但是用BLACK/RED/BLUE代表也可以这 ...
- jquery set selected for select element
//1$("#Provider_" + counter + " option[value=" + FormData.ID + "]").at ...
- sencha touch json store
js: Ext.define('MyApp.store.MyJsonStore', { extend: 'Ext.data.Store', requires: [ 'MyApp.model.Perso ...
- iOS8中的UIActionSheet添加UIDatePicker后,UIDatePicker不显示问题
解决方法: IOS8以前: UIActionSheet* startsheet = [[UIActionSheet alloc] initWithTitle:title delegate:self ...
- pptpvpn记录用户登录和流量信息
这个问题困扰了我很久,终于在pppd的man文档里,发现了踪迹.在man中的SCRIPTS下有一系列的参数,其中PEERNAME就是登陆的用户名,并且在/etc/ppp/ip-up和/etc/ppp/ ...
- [DP] The 0-1 knapsack problem
Give a dynamic-programming solution to the 0-1 knapsack problem that runs in O(nW) time, where n is ...