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 ...
随机推荐
- 网站开发常用jQuery插件总结(一)提示插件alertify
1.alertify插件功能 主要实现提示功能,用于代替js中的alert,confirm,prompt,显示友好的提示框 2.alertify官方地址 http://fabien-d.github. ...
- C#基础(五)——类中私有构造函数作用
如果类成员有private修饰符,就不允许在类范围以外访问这个类成员.对类构造函数应用private修饰符时,则禁止外部类创建该类的实例.尽管看上去有些不好理解(既然不能实例化,那么这个类还有什么用处 ...
- android的liveview装载数据
设置布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andro ...
- Missra开源前端框架
Missra开源前端框架,官方网址:http://framework.missra.com
- 51nod贪心算法入门-----独木舟问题
独木舟问题 n个人,已知每个人体重,独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? 分析:按照 ...
- Boost IPC Persistence Of Interprocess Mechanisms 例子
下面这一段摘抄自 Boost 1_55_0 的文档,显然标注了 每一个的生命期. One of the biggest issues with interprocess communication m ...
- 关于xcode6打包以及上线前企业部署测试的说明 --转自张诚教授微博
xcode6如何打包 首先clean然后点击归档 点击打包之后保存 点选第一个以后检查相关证书签名 那么我们开发完以后,在上线前如何给别人测试 有2种方法 1.使用299美金的企业开发者账号搭建企业部 ...
- Memcached(五)Memcached的并发实例
package com.sinosuperman.memcached; import java.io.IOException; import java.net.InetSocketAddress; i ...
- python 内置函数 getattr
class Getattr_Test(): var_a = 'abc' def methodA(self): var_b = 'xyz' return var_b t = Getattr_Test() ...
- Struts2 web.xml文件配置
在导入了项目需要使用的核心jar包之后需要在web.xml中配置Struts. 1. Struts2的知识点普及: Struts2共有5类配置文件,分别罗列如下: 1), Web.xml; 在没有使用 ...