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 0; }
1 //运行结果: 2 3 2016-06-05 18:07:55.919 copyTest2[2383:144656] array1 address = 0x1001025b0 4 2016-06-05 18:07:55.920 copyTest2[2383:144656] 5 2016-06-05 18:07:55.920 copyTest2[2383:144656] array2 address = 0x1001025b0 6 2016-06-05 18:07:55.920 copyTest2[2383:144656] 7 2016-06-05 18:07:55.920 copyTest2[2383:144656] array3 address = 0x1001025b0 8 2016-06-05 18:07:55.920 copyTest2[2383:144656] 9 2016-06-05 18:07:55.920 copyTest2[2383:144656] array4 address = 0x100102d20 10 Program ended with exit code: 0
结果分析:
(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:
1 //main.m 2 3 #import <Foundation/Foundation.h> 4 5 int main(int argc, const char * argv[]) { 6 @autoreleasepool { 7 // insert code here... 8 9 10 NSMutableArray *array1 = [[NSMutableArray alloc]initWithObjects: 11 [NSMutableString stringWithString:@"a"], 12 [NSMutableString stringWithString:@"b"], 13 [NSMutableString stringWithString:@"c"], 14 [NSMutableString stringWithString:@"d"], nil]; 15 16 NSMutableArray *array2; 17 NSMutableArray *array3; 18 NSMutableArray *array4; 19 20 NSMutableString *mStr = array1[0]; //定义一个可变字符串,用于在数组元素层面上修改数组元素 21 22 NSLog(@"Before array1 changes:"); 23 array2 = array1; 24 array3 = [array1 copy]; 25 array4 = [array1 mutableCopy]; 26 NSLog(@"array1 address is %p", array1); //array1指向的地址 27 NSLog(@"\narray1:%@", array1); //array1原始内容 28 NSLog(@"array2 address is %p", array2); //array2指向的地址 29 NSLog(@"\narray2:%@", array2); //array2原始内容 30 NSLog(@"array3 address is %p", array3); //array3指向的地址 31 NSLog(@"\narray3:%@", array3); //array3原始内容 32 NSLog(@"array4 address is %p", array4); //array4指向的地址 33 NSLog(@"\narray4:%@", array4); //array4原始内容 34 35 [array1 insertObject:@10000 atIndex:2]; //array1在数组的层面上修改 36 NSLog(@" "); 37 NSLog(@"After the first changes of array1:"); 38 NSLog(@"array1 address is %p", array1); //第一次修改后array1指向的地址 39 NSLog(@"\narray1:%@", array1); //第一次修改后array1的数据 40 NSLog(@"array2 address is %p", array2); //第一次修改后array2指向的地址 41 NSLog(@"\narray2:%@", array2); //第一次修改后array2的数据 42 NSLog(@"array3 address is %p", array3); //第一次修改后array3指向的地址 43 NSLog(@"\narray3:%@", array3); //第一次修改后array3的数据 44 NSLog(@"array4 address is %p", array4); //第一次修改后array4指向的地址 45 NSLog(@"\narray4:%@", array4); //第一次修改后array4的数据 46 47 48 [mStr appendString:@"AAAAAAAAAAAA"]; //在数组元素的层面上修改 49 NSLog(@" "); 50 NSLog(@"After the second changes of array1:"); 51 NSLog(@"array1 address is %p", array1); //第二次修改后array1指向的地址 52 NSLog(@"\narray1:%@", array1); //第二次修改后array1的数据 53 NSLog(@"array2 address is %p", array2); //第二次修改后array2指向的地址 54 NSLog(@"\narray2:%@", array2); //第二次修改后array2的数据 55 NSLog(@"array3 address is %p", array3); //第二次修改后array3指向的地址 56 NSLog(@"\narray3:%@", array3); //第二次修改后array3的数据 57 NSLog(@"array3 address is %p", array3); //第二次修改后array3指向的地址 58 NSLog(@"\narray3:%@", array3); //第二次修改后array3的数据 59 NSLog(@"array4 address is %p", array4); //第二次修改后array4指向的地址 60 NSLog(@"\narray4:%@", array4); //第二次修改后array4的数据 61 } 62 return 0; 63 }
1 //运行结果 2 3 2016-06-25 14:57:46.511 copyTest2[512:8667] Before array1 changes: 4 2016-06-25 14:57:46.512 copyTest2[512:8667] array1 address is 0x100108160 5 2016-06-25 14:57:46.512 copyTest2[512:8667] 6 array1:( 7 a, 8 b, 9 c, 10 d 11 ) 12 2016-06-25 14:57:46.512 copyTest2[512:8667] array2 address is 0x100108160 13 2016-06-25 14:57:46.512 copyTest2[512:8667] 14 array2:( 15 a, 16 b, 17 c, 18 d 19 ) 20 2016-06-25 14:57:46.512 copyTest2[512:8667] array3 address is 0x103101050 21 2016-06-25 14:57:46.512 copyTest2[512:8667] 22 array3:( 23 a, 24 b, 25 c, 26 d 27 ) 28 2016-06-25 14:57:46.512 copyTest2[512:8667] array4 address is 0x103101080 29 2016-06-25 14:57:46.512 copyTest2[512:8667] 30 array4:( 31 a, 32 b, 33 c, 34 d 35 ) 36 2016-06-25 14:57:46.512 copyTest2[512:8667] 37 2016-06-25 14:57:46.512 copyTest2[512:8667] After the first changes of array1: 38 2016-06-25 14:57:46.512 copyTest2[512:8667] array1 address is 0x100108160 39 2016-06-25 14:57:46.512 copyTest2[512:8667] 40 array1:( 41 a, 42 b, 43 10000, 44 c, 45 d 46 ) 47 2016-06-25 14:57:46.512 copyTest2[512:8667] array2 address is 0x100108160 48 2016-06-25 14:57:46.513 copyTest2[512:8667] 49 array2:( 50 a, 51 b, 52 10000, 53 c, 54 d 55 ) 56 2016-06-25 14:57:46.513 copyTest2[512:8667] array3 address is 0x103101050 57 2016-06-25 14:57:46.513 copyTest2[512:8667] 58 array3:( 59 a, 60 b, 61 c, 62 d 63 ) 64 2016-06-25 14:57:46.513 copyTest2[512:8667] array4 address is 0x103101080 65 2016-06-25 14:57:46.513 copyTest2[512:8667] 66 array4:( 67 a, 68 b, 69 c, 70 d 71 ) 72 2016-06-25 14:57:46.513 copyTest2[512:8667] 73 2016-06-25 14:57:46.513 copyTest2[512:8667] After the second changes of array1: 74 2016-06-25 14:57:46.513 copyTest2[512:8667] array1 address is 0x100108160 75 2016-06-25 14:57:46.513 copyTest2[512:8667] 76 array1:( 77 aAAAAAAAAAAAA, 78 b, 79 10000, 80 c, 81 d 82 ) 83 2016-06-25 14:57:46.513 copyTest2[512:8667] array2 address is 0x100108160 84 2016-06-25 14:57:46.513 copyTest2[512:8667] 85 array2:( 86 aAAAAAAAAAAAA, 87 b, 88 10000, 89 c, 90 d 91 ) 92 2016-06-25 14:57:46.513 copyTest2[512:8667] array3 address is 0x103101050 93 2016-06-25 14:57:46.513 copyTest2[512:8667] 94 array3:( 95 aAAAAAAAAAAAA, 96 b, 97 c, 98 d 99 ) 100 2016-06-25 14:57:46.513 copyTest2[512:8667] array3 address is 0x103101050 101 2016-06-25 14:57:46.513 copyTest2[512:8667] 102 array3:( 103 aAAAAAAAAAAAA, 104 b, 105 c, 106 d 107 ) 108 2016-06-25 14:57:46.514 copyTest2[512:8667] array4 address is 0x103101080 109 2016-06-25 14:57:46.514 copyTest2[512:8667] 110 array4:( 111 aAAAAAAAAAAAA, 112 b, 113 c, 114 d 115 ) 116 Program ended with exit code: 0
这次先上图:
图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对象:
1 //main.m 2 3 #import <Foundation/Foundation.h> 4 5 int main(int argc, const char * argv[]) { 6 @autoreleasepool { 7 NSData *data; 8 NSMutableArray *dataArray = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"one"],[NSMutableString stringWithString:@"two"],[NSMutableString stringWithString:@"three"], nil]; 9 10 NSMutableArray *dataArray2 ; 11 NSMutableString *mStr; 12 13 //使用归档器进行深复制 14 data = [NSKeyedArchiver archivedDataWithRootObject:dataArray]; 15 16 dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 17 18 mStr = dataArray2[0]; 19 [mStr appendString:@"ONE"]; 20 21 22 NSLog(@"dataArray:"); 23 for(NSString *elem in dataArray) 24 { 25 NSLog(@"%@", elem); 26 } 27 NSLog(@"\ndataArray2:"); 28 for(NSString *elem in dataArray2) 29 { 30 NSLog(@"%@", elem); 31 } 32 33 //查看dataArray和dataArray2两个可变数组的地址 34 NSLog(@"\n"); 35 NSLog(@"%p", dataArray); 36 NSLog(@"%p", dataArray2); 37 38 //查看dataArray和dataArray2两个可变数组首个元素的地址 39 NSLog(@"\n"); 40 NSLog(@"%p", dataArray[0]); 41 NSLog(@"%p", dataArray2[0]); 42 } 43 return 0; 44 } 45
1 //运行结果: 2 3 4 2016-07-02 12:54:13.426 Objective-C-p450[1122:29001] dataArray: 5 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] one 6 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] two 7 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] three 8 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] 9 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] dataArray2: 10 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] oneONE 11 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] two 12 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] three 13 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] 14 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] 0x1007005e0 15 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] 0x100703850 16 2016-07-02 12:54:13.427 Objective-C-p450[1122:29001] 17 2016-07-02 12:54:13.428 Objective-C-p450[1122:29001] 0x100700250 18 2016-07-02 12:54:13.428 Objective-C-p450[1122:29001] 0x100702720 19 Program ended with exit code: 0
图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],更清晰地看到它们的地址完全不同。