深拷貝
,
淺拷貝
,
copy
,
mutableCopy
,
單層拷貝
面試題:
1)什麼是深拷貝什麼是淺拷貝?
2)對可變對象進行copy是深拷貝仍是淺拷貝?
3)爲何給NSString類型屬性使用copy修飾,改成strong能夠嗎?
4)@property (copy) NSMutableArray *array; 這種寫法有什麼問題?
5)什麼是單層拷貝,怎麼實現多層拷貝?
6)修飾block屬性時,爲何用copy?
面試
淺拷貝:
淺拷貝就是對內存地址的複製,讓目標對象指針和源對象指向同一片內存空間,當內存銷燬的時候,指向這片內存的幾個指針須要從新定義纔可使用,要否則會成爲野指針。
深拷貝:
深拷貝是指拷貝對象的具體內容,而內存地址是自主分配的,拷貝結束以後,兩個對象雖然存的值是相同的,可是內存地址不同,兩個對象也互不影響,互不干涉。
數組
【總結】
深拷貝就是內容拷貝,淺拷貝就是指針拷貝。本質區別在於:
bash
使用copy或mutableCopy方法能夠建立一個對象的副本。性能
copy:
須要實現NSCoppying協議;
這些建立的是不可變副本(如NSString、NSArray、NSDictionary);
mutableCopy:
須要先實現NSMutableCopying協議;
建立的是可變副本(如NSMutableString、NSMutableArray、NSMutableDictionary);
atom
NSString *str = @"不可變對象";
NSString *copyStr = [str copy];
NSLog(@"str=%@, 地址:%p",str, str);
NSLog(@"copyStr=%@, 地址:%p",copyStr, copyStr);
// 打印:
2020-07-05 10:59:46.208267+0800 OCTestDemo[77626:1744180] str=不可變對象, 地址:0x108704330
2020-07-05 10:59:46.208372+0800 OCTestDemo[77626:1744180] copyStr=不可變對象, 地址:0x108704330
// 結論:對不可變對象copy,是淺拷貝。
複製代碼
NSString *str = @"不可變對象";
NSString *mtCopyStr = [str mutableCopy];
NSLog(@"str=%@, 地址:%p",str, str);
NSLog(@"mtCopyStr=%@, 地址:%p",mtCopyStr, mtCopyStr);
// 打印:
2020-07-05 11:01:20.982338+0800 OCTestDemo[77699:1746254] str=不可變對象, 地址:0x10fa86330
2020-07-05 11:01:20.982470+0800 OCTestDemo[77699:1746254] mtCopyStr=不可變對象, 地址:0x600000257fa0
// 結論:對不可變對象mutableCopy,是深拷貝。
複製代碼
NSMutableString *str = [NSMutableString stringWithString:@"可變對象"];
NSString *copyStr = [str copy];
NSLog(@"str=%@, 地址:%p",str, str);
NSLog(@"copyStr=%@, 地址:%p",copyStr, copyStr);
// 打印:
2020-07-05 11:04:04.408830+0800 OCTestDemo[77768:1748628] str=可變對象, 地址:0x60000024c900
2020-07-05 11:04:04.408933+0800 OCTestDemo[77768:1748628] copyStr=可變對象, 地址:0x6000002279a0
// 結論:對可變對象copy,是深拷貝。
複製代碼
NSMutableString *str = [NSMutableString stringWithString:@"可變對象"];
NSString *mtCopyStr = [str mutableCopy];
NSLog(@"str=%@, 地址:%p",str, str);
NSLog(@"mtCopyStr=%@, 地址:%p",mtCopyStr, mtCopyStr);
// 打印:
2020-07-05 11:05:38.838961+0800 OCTestDemo[77828:1750661] str=可變對象, 地址:0x600000256200
2020-07-05 11:05:38.839065+0800 OCTestDemo[77828:1750661] mtCopyStr=可變對象, 地址:0x60000025e8d0
// 結論:對可變對象mutableCopy,是深拷貝。
複製代碼
Animal *dog = [[Animal alloc]init];
Animal *cat = [[Animal alloc]init];
Animal *pig = [[Animal alloc]init];
複製代碼
NSArray *arr = @[dog, cat, pig];
NSArray *copyArr = [arr copy];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"copyArr=%@, 地址:%p",copyArr, copyArr);
// 打印:
2020-07-05 11:10:12.324873+0800 OCTestDemo[77897:1754011] arr=(
"<Animal: 0x600000015fc0>",
"<Animal: 0x600000015670>",
"<Animal: 0x600000015220>"
), 地址:0x6000004598f0
2020-07-05 11:10:12.325063+0800 OCTestDemo[77897:1754011] copyArr=(
"<Animal: 0x600000015fc0>",
"<Animal: 0x600000015670>",
"<Animal: 0x600000015220>"
), 地址:0x6000004598f0
// 結論:對不可變容器對象copy,是淺拷貝,且爲單層拷貝。
複製代碼
NSArray *arr = @[dog, cat, pig];
NSArray *mtCopyArr = [arr mutableCopy];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"mtCopyArr=%@, 地址:%p",mtCopyArr, mtCopyArr);
// 打印:
2020-07-05 11:12:30.281808+0800 OCTestDemo[77952:1756412] arr=(
"<Animal: 0x604000202810>",
"<Animal: 0x6040000178c0>",
"<Animal: 0x604000017c70>"
), 地址:0x60400024c7b0
2020-07-05 11:12:30.281930+0800 OCTestDemo[77952:1756412] mtCopyArr=(
"<Animal: 0x604000202810>",
"<Animal: 0x6040000178c0>",
"<Animal: 0x604000017c70>"
), 地址:0x60400024d020
// 結論:對不可變容器對象mutableCopy,是深拷貝,且爲單層拷貝。
複製代碼
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *copyArr = [arr copy];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"copyArr=%@, 地址:%p",copyArr, copyArr);
// 打印:
2020-07-05 11:15:05.863855+0800 OCTestDemo[78006:1758411] arr=(
"<Animal: 0x60400001e990>",
"<Animal: 0x60400001e400>",
"<Animal: 0x60400001e390>"
), 地址:0x60400024b040
2020-07-05 11:15:05.864007+0800 OCTestDemo[78006:1758411] copyArr=(
"<Animal: 0x60400001e990>",
"<Animal: 0x60400001e400>",
"<Animal: 0x60400001e390>"
), 地址:0x60400024af50
// 結論:對可變容器對象copy,是深拷貝,且爲單層拷貝。
複製代碼
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *mtCopyArr = [arr mutableCopy];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"mtCopyArr=%@, 地址:%p",mtCopyArr, mtCopyArr);
// 打印:
2020-07-05 11:16:56.869198+0800 OCTestDemo[78056:1760281] arr=(
"<Animal: 0x600000013270>",
"<Animal: 0x600000012fb0>",
"<Animal: 0x600000013b70>"
), 地址:0x6000004403c0
2020-07-05 11:16:56.869378+0800 OCTestDemo[78056:1760281] mtCopyArr=(
"<Animal: 0x600000013270>",
"<Animal: 0x600000012fb0>",
"<Animal: 0x600000013b70>"
), 地址:0x600000440480
// 結論:對可變容器對象mutableCopy,是深拷貝,且爲單層拷貝。
複製代碼
- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *deepCopyArr = [[NSArray alloc]initWithArray:arr copyItems:YES];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"deepCopyArr=%@, 地址:%p",deepCopyArr, deepCopyArr);
// 打印:
2020-07-05 11:27:19.171118+0800 OCTestDemo[78309:1769460] arr=(
"<Animal: 0x600000000df0>",
"<Animal: 0x6000000006b0>",
"<Animal: 0x600000000cd0>"
), 地址:0x600000254850
2020-07-05 11:27:19.171313+0800 OCTestDemo[78309:1769460] deepCopyArr=(
"<Animal: 0x600000000b70>",
"<Animal: 0x600000000dc0>",
"<Animal: 0x600000000d80>"
), 地址:0x6000002544f0
// 結論:使用initWithArray:copyItems:方法能夠達到多層拷貝的效果,但這裏也只是雙重拷貝,並非真正意義上的多層拷貝。
// 注意,數組內的元素須要實現NSCopying,NSMutableCopying協議。
複製代碼
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *deepCopyArr = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arr]];
NSLog(@"arr=%@, 地址:%p",arr, arr);
NSLog(@"deepCopyArr=%@, 地址:%p",deepCopyArr, deepCopyArr);
// 打印:
2020-07-05 11:38:08.175207+0800 OCTestDemo[78604:1779461] arr=(
"<Animal: 0x60000000ab90>",
"<Animal: 0x60000000ab70>",
"<Animal: 0x600000010bf0>"
), 地址:0x60000044f5a0
2020-07-05 11:38:08.175351+0800 OCTestDemo[78604:1779461] deepCopyArr=(
"<Animal: 0x600000010f70>",
"<Animal: 0x600000010ef0>",
"<Animal: 0x600000010f60>"
), 地址:0x60000044f600
// 結論:使用歸檔解檔方法能夠達到多層拷貝的效果。注意,數組內的元素須要實現NSCoding協議。
複製代碼
NSString、NSArray、NSDictionary等等常常使用copy關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary;
spa
copy 此特質所表達的所屬關係與 strong 相似。然而設置方法並不保留新值,而是將其「拷貝」 (copy)。 當屬性類型爲 NSString 時,常常用此特質來保護其封裝性,由於傳遞給設置方法的新值有可能指向一個 NSMutableString 類的實例。
指針
用 @property 聲明 NSString、NSArray、NSDictionary 常常使用 copy 關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操做,爲確保對象中的字符串值不會無心間變更,應該在設置新屬性值時拷貝一份。code
block 使用 copy 是從 MRC 遺留下來的「傳統」,在 MRC 中,方法內部的 block 是在棧區的,使用 copy 能夠把它放到堆區。在 ARC 中寫不寫都行:對於 block 使用 copy 仍是 strong 效果是同樣的,但寫上 copy 也無傷大雅,還能時刻提醒咱們:編譯器自動對 block 進行了 copy 操做。cdn
@property (copy) NSMutableArray *array;
這種寫法有什麼問題?兩個問題:
一、添加,刪除,修改數組內的元素的時候,程序會由於找不到對應的方法而崩潰。由於 copy 就是複製一個不可變 NSArray 的對象;
二、使用了 atomic 屬性會嚴重影響性能;
對象