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的更多相关文章

  1. --NSArray与NSMutableArray用copy修饰还是strong(转)

    一.NSMutableArray 被copy.strong修饰后的变化: 把NSMutableArray用copy修饰有时就会crash,因为对这个数组进行了增删改操作,而copy后的数组变成了不可变 ...

  2. iOS之NSArray类簇简介-(copy、mutableCopy导致程序crash)

    1.前言 开发时常常用数组对数据进行处理,对NSMutableArray进行操作时经常导致程序崩溃,特研究一下NSArray的类簇!涉及__NSPlaceholderArray.__NSArray0. ...

  3. Objective-C中的Strong、Copy与MutableCopy

    面试过程中经常被问到ARC中Strong.Copy的区别是什么.普通的回答是:一样.文艺(正确)的回答是:分情况(我擦!WQY#$&Y**%OWEUR) 可以先参考这篇文章http://www ...

  4. 对copy、mutableCopy理解

    Objective - C 中有很多在日常项目中经常用到的常用代码,在这里着重的讲一下关于copy 和 mutableCopy 的区别以及相关用法. Objective - C 中可变对象和不可对象经 ...

  5. 集合使用copy与mutableCopy的区别

    集合(NSArray,NSSet,NSDictionary等)使用copy与mutableCopy的区别是类似的,下面以NSMutableArray.NSArray 为例子验证如下: NSMutabl ...

  6. iOS Copy 和 MutableCopy的区别 深浅拷贝的区别-供参考

    概述 对于系统的非容器类对象,对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝).如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的. 对于 ...

  7. 【转】copy 和 mutablecopy (深拷贝和浅拷贝)

    阅读本文之前首先了解copy与retain的区别,如果有不正确的地方望大家多多指教: copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属 ...

  8. copy和mutableCopy的深、浅拷贝

    对象拷贝主要由两种方式:copy和mutableCopy.浅拷贝是指直接将指针指向原有的地址,从而达到复制的目的.深拷贝是指重新生成一个对象,将原有对象的内容复制到新的对象中.copy 返回的是一个不 ...

  9. NSArray 与 NSMutableArray 的排序

    由于集合的使用过程中,经常需要对数组进行排序操作,此博客用于总结对在OC中对数组排序的几种方法 1.当数组中存放的是Foundation框架中提供的对象时,直接使用 compare:方法 如:NSSt ...

随机推荐

  1. 网站开发常用jQuery插件总结(一)提示插件alertify

    1.alertify插件功能 主要实现提示功能,用于代替js中的alert,confirm,prompt,显示友好的提示框 2.alertify官方地址 http://fabien-d.github. ...

  2. C#基础(五)——类中私有构造函数作用

    如果类成员有private修饰符,就不允许在类范围以外访问这个类成员.对类构造函数应用private修饰符时,则禁止外部类创建该类的实例.尽管看上去有些不好理解(既然不能实例化,那么这个类还有什么用处 ...

  3. android的liveview装载数据

    设置布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andro ...

  4. Missra开源前端框架

    Missra开源前端框架,官方网址:http://framework.missra.com

  5. 51nod贪心算法入门-----独木舟问题

    独木舟问题 n个人,已知每个人体重,独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? 分析:按照 ...

  6. Boost IPC Persistence Of Interprocess Mechanisms 例子

    下面这一段摘抄自 Boost 1_55_0 的文档,显然标注了 每一个的生命期. One of the biggest issues with interprocess communication m ...

  7. 关于xcode6打包以及上线前企业部署测试的说明 --转自张诚教授微博

    xcode6如何打包 首先clean然后点击归档 点击打包之后保存 点选第一个以后检查相关证书签名 那么我们开发完以后,在上线前如何给别人测试 有2种方法 1.使用299美金的企业开发者账号搭建企业部 ...

  8. Memcached(五)Memcached的并发实例

    package com.sinosuperman.memcached; import java.io.IOException; import java.net.InetSocketAddress; i ...

  9. python 内置函数 getattr

    class Getattr_Test(): var_a = 'abc' def methodA(self): var_b = 'xyz' return var_b t = Getattr_Test() ...

  10. Struts2 web.xml文件配置

    在导入了项目需要使用的核心jar包之后需要在web.xml中配置Struts. 1. Struts2的知识点普及: Struts2共有5类配置文件,分别罗列如下: 1), Web.xml; 在没有使用 ...