1) 对于非容器类对象如NSString, NSNumber之类的而言
NSString *str1 = @"abc";
NSString *str2 = [str1 copy]; // 地址和Str1一样
NSString *str3 = [str1 mutableCopy]; // 地址和str1不同, 虽然是深拷贝,但无法修改str3内容(语法不通过)
NSMutableString *str4 = [str1 copy]; // 地址和Str一样, 修改Str4会崩溃
NSMutableString *str5 = [str1 mutableCopy]; // 地址和str1 不同
NSLog(@"str1 ===== %p", str1);
NSLog(@"str2 ===== %p", str2);
NSLog(@"str3 ===== %p", str3);
NSLog(@"str4 ===== %p", str4);
NSLog(@"str5 ===== %p", str5);
[str3 appendString:@"xxx"]; // 报错,语法错误
[str4 appendString:@"xxx"]; // 会导致程序崩溃. reason: ‘Attempt to mutate immutable object with appendString:‘
执行结果:
2015-09-13 22:08:58.958 test[8507:69904] str1 ===== 0x105b407d0
2015-09-13 22:08:58.959 test[8507:69904] str2 ===== 0x105b407d0
2015-09-13 22:08:58.959 test[8507:69904] str3 ===== 0x7fdfc042b150
2015-09-13 22:08:58.959 test[8507:69904] str4 ===== 0x105b407d0
2015-09-13 22:08:58.959 test[8507:69904] str5 ===== 0x7fdfc042ca60
// =============================================
NSMutableString *str1 = [NSMutableString stringWithFormat:@"abc"]; NSString *str2 = [str1 copy]; // 地址和Str1不同 NSString *str3 = [str1 mutableCopy]; // 地址和str1不同, 虽然是深拷贝,但无法修改str3内容(语法不通过) NSMutableString *str4 = [str1 copy]; // 地址和Str1不同, str4本质是NSString而不是NSMutableString, 修改Str4会崩溃 NSMutableString *str5 = [str1 mutableCopy]; // 地址和str1 不同 NSLog(@"str1 ===== %p", str1); NSLog(@"str2 ===== %p", str2); NSLog(@"str3 ===== %p", str3); NSLog(@"str4 ===== %p", str4); NSLog(@"str5 ===== %p", str5);
执行结果:
2015-09-13 22:55:32.116 test[11538:104525] str1 ===== 0x7fab3949b140
2015-09-13 22:55:32.117 test[11538:104525] str2 ===== 0x7fab3949e5d0
2015-09-13 22:55:32.117 test[11538:104525] str3 ===== 0x7fab39490970
2015-09-13 22:55:32.117 test[11538:104525] str4 ===== 0x7fab394975a0
2015-09-13 22:55:32.117 test[11538:104525] str5 ===== 0x7fab3949e470
结论: 对于可变类型的拷贝(copy/mutableCopy)都是深拷贝, 但使用copy返回的对象的真实类型是不可变的, 修改它会导致程序崩溃; 对于不可变类型的copy是浅拷贝, mutableCopy是深拷贝.
2) 对于容器类对象如NSArray, NSDictionary之类的而言
NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithFormat:@"a"], @"b", @"c", nil];
NSArray *array2 = [array1 copy]; // 地址与array1一样
NSArray *array3 = [array1 mutableCopy]; // 地址与array1不同
NSMutableArray *array4 = [array1 copy]; // 地址与array1一样
NSMutableArray *array5 = [array1 mutableCopy]; // 地址与array1不样
NSArray *array6 = [[NSArray alloc] initWithArray:array1 copyItems:YES]; // 地址与array1不同, 容器内的可变元素深拷贝, 而不可变元素依然是浅拷贝.
NSArray *array7 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1]]; // 地址与array1不同, 容器内的元素都进行深拷贝
NSMutableString *str = array5[0];
[str appendString:@"xxx"];
NSMutableString *str2 = array5[1];
// [str2 appendString:@"xxx"]; // 会导致程序崩溃.
NSLog(@"array1 ==== %p", array1);
NSLog(@"array2 ==== %p", array2);
NSLog(@"array3 ==== %p", array3);
NSLog(@"array4 ==== %p", array4);
NSLog(@"array5 ==== %p", array5);
NSLog(@"array6 ==== %p", array6);
NSLog(@"array7 ==== %p", array7);
NSLog(@"array1[0] ==== %p", array1[0]);
NSLog(@"array2[0] ==== %p", array2[0]);
NSLog(@"array3[0] ==== %p", array3[0]);
NSLog(@"array4[0] ==== %p", array4[0]);
NSLog(@"array5[0] ==== %p", array5[0]);
NSLog(@"array6[0] ==== %p", array6[0]);
NSLog(@"array7[0] ==== %p", array7[0]);
NSLog(@"array1[1] ==== %p", array1[1]);
NSLog(@"array2[1] ==== %p", array2[1]);
NSLog(@"array3[1] ==== %p", array3[1]);
NSLog(@"array4[1] ==== %p", array4[1]);
NSLog(@"array5[1] ==== %p", array5[1]);
NSLog(@"array6[1] ==== %p", array6[1]);
NSLog(@"array7[1] ==== %p", array7[1]);
NSLog(@"array1[0] ==== %@", array1[0]);
NSLog(@"array2[0] ==== %@", array2[0]);
NSLog(@"array3[0] ==== %@", array3[0]);
NSLog(@"array4[0] ==== %@", array4[0]);
NSLog(@"array5[0] ==== %@", array5[0]);
NSLog(@"array6[0] ==== %@", array6[0]);
NSLog(@"array7[0] ==== %@", array7[0]);
执行结果:
2015-09-13 23:15:46.235 test[12791:118074] array1 ==== 0x7fc6e1d1dab0
2015-09-13 23:15:46.236 test[12791:118074] array2 ==== 0x7fc6e1d1dab0
2015-09-13 23:15:46.236 test[12791:118074] array3 ==== 0x7fc6e1d2ef40
2015-09-13 23:15:46.236 test[12791:118074] array4 ==== 0x7fc6e1d1dab0
2015-09-13 23:15:46.236 test[12791:118074] array5 ==== 0x7fc6e1d19430
2015-09-13 23:15:46.236 test[12791:118074] array6 ==== 0x7fc6e1d2fc60
2015-09-13 23:15:46.236 test[12791:118074] array7 ==== 0x7fc6e1c30cd0
2015-09-13 23:15:46.237 test[12791:118074] array1[0] ==== 0x7fc6e1d1ba10
2015-09-13 23:15:46.237 test[12791:118074] array2[0] ==== 0x7fc6e1d1ba10
2015-09-13 23:15:46.237 test[12791:118074] array3[0] ==== 0x7fc6e1d1ba10
2015-09-13 23:15:46.237 test[12791:118074] array4[0] ==== 0x7fc6e1d1ba10
2015-09-13 23:15:46.237 test[12791:118074] array5[0] ==== 0x7fc6e1d1ba10
2015-09-13 23:15:46.237 test[12791:118074] array6[0] ==== 0x7fc6e1d2fc40
2015-09-13 23:15:46.238 test[12791:118074] array7[0] ==== 0x7fc6e1c2faf0
2015-09-13 23:15:46.238 test[12791:118074] array1[1] ==== 0x10fd197f0
2015-09-13 23:15:46.238 test[12791:118074] array2[1] ==== 0x10fd197f0
2015-09-13 23:15:46.238 test[12791:118074] array3[1] ==== 0x10fd197f0
2015-09-13 23:15:46.238 test[12791:118074] array4[1] ==== 0x10fd197f0
2015-09-13 23:15:46.239 test[12791:118074] array5[1] ==== 0x10fd197f0
2015-09-13 23:15:46.239 test[12791:118074] array6[1] ==== 0x10fd197f0
2015-09-13 23:15:46.239 test[12791:118074] array7[1] ==== 0x7fc6e1c2fc50
2015-09-13 23:15:46.239 test[12791:118074] array1[0] ==== axxx
2015-09-13 23:15:46.239 test[12791:118074] array2[0] ==== axxx
2015-09-13 23:15:46.239 test[12791:118074] array3[0] ==== axxx
2015-09-13 23:15:46.240 test[12791:118074] array4[0] ==== axxx
2015-09-13 23:15:46.240 test[12791:118074] array5[0] ==== axxx
2015-09-13 23:15:46.240 test[12791:118074] array6[0] ==== a
2015-09-13 23:15:46.240 test[12791:118074] array7[0] ==== a
结论: 对于非容器类对象的结论同样适用于容器类对象, 只是容器类对象内的元素始终都只是浅拷贝. 若要对容器内的元素也进行真正意义上的深拷贝, 可以采用归档解档的方式进行.
官方相关链接:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html