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所示:

NSArray和NSMutableArray的copy和MutableCopy-LMLPHP

图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:

这次先上图:

NSArray和NSMutableArray的copy和MutableCopy-LMLPHP

图2(改变前)

NSArray和NSMutableArray的copy和MutableCopy-LMLPHP

图3(第一次改变后)

NSArray和NSMutableArray的copy和MutableCopy-LMLPHP

图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:

NSArray和NSMutableArray的copy和MutableCopy-LMLPHP

图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],更清晰地看到它们的地址完全不同。

04-28 18:35