前言
前段時間射亏,看到在知識小集的交流群里正在討論 copy
和 mutableCopy
這兩個方法的相關(guān)特性琢唾。而這兩個方法的使用寡壮,對于 Collection
來說咳促,確實(shí)在運(yùn)行的時候會有些不一樣。主要還是為了記錄一下襟沮,避免以后忘記锥惋,所以寫了這篇文章。
理論概述
本文章將會討論 CoreFoundation
和 Foundation
框架里面的 Collection
類,當(dāng)然也會簡單的講述自己定義的類,怎么實(shí)現(xiàn) copy
和 mutableCopy
方法菇夸。
Collection 類的結(jié)論概括
首先铁孵,先查看有關(guān) Collection
類的總結(jié)。當(dāng)然,以下表格總結(jié)的結(jié)論只驗(yàn)證過一下這些類 NSString
、NSMutableString
、NSArray
丛忆、NSMutableArray
、NSDictionary
仍秤、NSMutableDictionary
熄诡、NSSet
和 NSMutableSet
。
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NS* | copy | NO | NS* | NO | NO | 淺拷貝 | NO |
mutableCopy | YES | NSMutable* | NO | NO | 深拷貝 | NO | |
NSMutable* | copy | YES | NS* | NO | NO | 深拷貝 | NO |
mutableCopy | YES | NSMutable* | NO | NO | 深拷貝 | NO |
由以上表格可以得出以下結(jié)論:
Collection
類(容器)所有的 Copy 操作都只是對容器操作诗力,不會對容器里的元素進(jìn)行 Copy 操作凰浮。只有
NS
開頭的不可變字符串/數(shù)組/字典等集合類型調(diào)用copy
方法才是淺拷貝(指針拷貝),不會生成新容器對象苇本;其余的情況袜茧,則是深拷貝(內(nèi)容拷貝),會生成對應(yīng)的新容器對象瓣窄,但容器內(nèi)的元素還是原來的元素笛厦。調(diào)用
copy
方法輸出的是NS
開頭的不可變字符串/數(shù)組/字典等集合類型,調(diào)用mutableCopy
方法輸出的是NSMutable
開頭的可變字符串/數(shù)組/字典等集合類型(這里說的是輸出的類型俺夕,不一定產(chǎn)生新容器對象)裳凸。
自定義類的結(jié)論概括
自定義類,調(diào)用 copy
和 mutableCopy
方法的輸出規(guī)則其實(shí)主要還是看自己實(shí)現(xiàn)的代碼控制啥么。
需要自定義類實(shí)現(xiàn) copy
方法登舞,就必須遵守 NSCopying
協(xié)議,并實(shí)現(xiàn) - (id)copyWithZone:(NSZone *)zone
方法悬荣,詳情請看以下代碼:
@interface Person : NSObject <NSCopying>
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone {
//這里需要Copy操作返回什么,就會輸出什么
return self;
}
@end
需要自定義類實(shí)現(xiàn) mutableCopy
方法疙剑,就必須遵守 NSMutableCopying
協(xié)議氯迂,并實(shí)現(xiàn) - (id)mutableCopyWithZone:(NSZone *)zone
方法践叠,詳情請看以下代碼:
@interface Person : NSObject <NSMutableCopying>
@end
@implementation Person
- (id)mutableCopyWithZone:(NSZone *)zone {
//這里需要mutableCopy操作返回什么,就會輸出什么
return [[[self class] alloc] init];
}
@end
驗(yàn)證結(jié)論概括
接下來的章節(jié)就是驗(yàn)證以上的結(jié)論的過程嚼蚀,不過這里需要注意的是驗(yàn)證過程中打印出來的類名都是 NS*
和 NSMutable*
的 Class Clusters(類簇)禁灼。
Apple 文檔中是這樣描述:
an architecture that groups a number of private, concrete subclasses under a public, abstract superclass. (一個在共有的抽象超類下設(shè)置一組私有子類的架構(gòu))
Class cluster
是 Apple 對抽象工廠設(shè)計模式的稱呼。使用抽象類初始化返回一個具體的子類的模式的好處就是讓調(diào)用者只需要知道抽象類開放出來的API的作用轿曙,而不需要知道子類的背后復(fù)雜的邏輯弄捕。驗(yàn)證結(jié)論過程的類簇對應(yīng)關(guān)系請看這篇 Class Clusters 文檔。
NSString
首先导帝,驗(yàn)證字符串常量 NSString
調(diào)用 copy
和 mutableCopy
的情況守谓。運(yùn)行以下的測試代碼:
NSString *str = @"abc"; // __NSCFConstantString
NSString *copyStr = [str copy]; // __NSCFConstantString
NSMutableString *mutableCopyStr = [str mutableCopy]; // __NSCFString
NSLog(@"str(%@<%p>: %p): %@", [str class], &str, str, str);
NSLog(@"copyStr(%@<%p>: %p): %@", [copyStr class], ©Str, copyStr, copyStr);
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
[mutableCopyStr appendString:@"add"];
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 15:17:00.323254+0800 TestCocoOC[12366:898331] str(__NSCFConstantString<0x7ffee96d80c8>: 0x106529148): abc
2018-08-17 15:17:00.323383+0800 TestCocoOC[12366:898331] copyStr(__NSCFConstantString<0x7ffee96d80c0>: 0x106529148): abc
2018-08-17 15:17:00.323637+0800 TestCocoOC[12366:898331] mutableCopyStr(__NSCFString<0x7ffee96d80b8>: 0x60c000240870): abc
2018-08-17 15:17:00.323855+0800 TestCocoOC[12366:898331] mutableCopyStr(__NSCFString<0x7ffee96d80b8>: 0x60c000240870): abcadd
2018-08-17 15:17:00.323918+0800 TestCocoOC[12366:898331] end
Class Clusters 分析:
-
__NSCFConstantString
是字符串常量類,可看作NSString
您单。 -
__NSCFString
是字符串類斋荞,通常可看作NSMutableString
虐秦。
根據(jù)以上測試代碼和打印的結(jié)果顯示平酿,可進(jìn)行以下分析:
- 變量
str
和copyStr
打印出來的地址是相同的,都是0x106529148
而且類名相同悦陋,都是__NSCFConstantString
蜈彼,說明只是淺拷貝,而且是NSString
俺驶。 - 變量
mutableCopyStr
打印出的類名__NSCFString
幸逆,和其他的結(jié)果不一樣,而且能夠添加字符串痒钝,所以是NSMutableString
秉颗。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSString | copy | NO | NSString | NO | NO | 淺拷貝 | NO |
mutableCopy | YES | NSMutableString | NO | NO | 深拷貝 | NO |
NSMutableString
可變字符串的 copy
和 mutableCopy
操作,測試代碼如下:
NSMutableString *str = [NSMutableString stringWithString:@"abc"]; // __NSCFString
NSMutableString *copyStr = [str copy]; //NSTaggedPointerString
NSMutableString *mutableCopyStr = [str mutableCopy]; // __NSCFString
NSLog(@"str(%@<%p>: %p): %@", [str class], &str, str, str);
NSLog(@"copyStr(%@<%p>: %p): %@", [copyStr class], ©Str, copyStr, copyStr);
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:39:26.601180+0800 TestCocoOC[9649:625978] str(__NSCFString<0x7ffeef6130c8>: 0x6000000599b0): abc
2018-08-17 13:39:26.601411+0800 TestCocoOC[9649:625978] copyStr(NSTaggedPointerString<0x7ffeef6130c0>: 0xa000000006362613): abc
2018-08-17 13:39:26.601701+0800 TestCocoOC[9649:625978] mutableCopyStr(__NSCFString<0x7ffeef6130b8>: 0x60000005ad00): abc
2018-08-17 13:39:26.602004+0800 TestCocoOC[9649:625978] end
Class Clusters 分析:
-
NSTaggedPointerString
是字符串常量類送矩,可看作NSString
蚕甥,這個類具備Tagged Pointer
特性。 -
__NSCFString
是字符串類栋荸,通彻交常可看作NSMutableString
。
根據(jù)打印的結(jié)果可得出以下分析:
-
str
晌块、copyStr
和mutableCopyStr
指針指向的地址都是不一樣的爱沟,說明都生成了新對象。 -
copy
方法生成不可變字符串對象匆背,mutableCopy
方法生成的是可變字符串對象呼伸。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSMutableString | copy | YES | NSString | NO | NO | 深拷貝 | NO |
mutableCopy | YES | NSMutableString | NO | NO | 深拷貝 | NO |
NSArray
數(shù)組的拷貝操作,都是針對數(shù)組容器對象處理钝尸,數(shù)組里面的元素對象都是不變的括享。測試代碼如下:
Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSArray *array = @[person1, person2, person3]; //__NSArrayI
NSArray *copyArray = [array copy]; //__NSArrayI
NSArray *mutableCopyArray = [array mutableCopy]; //__NSArrayM
NSLog(@"array(%@<%p>: %p): %@", [array class], &array, array, array);
NSLog(@"copyArray(%@<%p>: %p): %@", [copyArray class], ©Array, copyArray, copyArray);
NSLog(@"mutableCopyArray(%@<%p>: %p): %@", [mutableCopyArray class], &mutableCopyArray, mutableCopyArray, mutableCopyArray);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:39:43.724273+0800 TestCocoOC[9649:625978] array(__NSArrayI<0x7ffeef613090>: 0x60c00024c3f0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724481+0800 TestCocoOC[9649:625978] copyArray(__NSArrayI<0x7ffeef613088>: 0x60c00024c3f0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724713+0800 TestCocoOC[9649:625978] mutableCopyArray(__NSArrayM<0x7ffeef613080>: 0x60c00024c2a0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724984+0800 TestCocoOC[9649:625978] end
Class Clusters 分析:
-
__NSArrayI
是不可變數(shù)組子類搂根,可看作NSArray
。 -
__NSArrayM
是可變數(shù)組子類铃辖,通呈@ⅲ可看作NSMutableArray
。
根據(jù)以上測試代碼和打印的結(jié)果顯示娇斩,可進(jìn)行以下分析:
- 變量
array
和copyArray
打印出來的地址是相同的仁卷,都是0x60c00024c3f0
而且類名相同,都是__NSArrayI
犬第,說明只是淺拷貝锦积,而且是NSArray
。 - 變量
mutableCopyStr
打印出的類名__NSArrayM
瓶殃,所以是NSMutableArray
充包。 - 數(shù)組里的元素打印的對象地址都是一樣的。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSArray | copy | NO | NSArray | NO | NO | 淺拷貝 | NO |
mutableCopy | YES | NSMutableArray | NO | NO | 深拷貝 | NO |
NSMutableArray
不可變數(shù)組和可變數(shù)組的關(guān)系其實(shí)是子類和父類的關(guān)系遥椿。以下就是驗(yàn)證可變數(shù)組拷貝操作的測試代碼:
Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[person1, person2, person3]]; // __NSArrayM
//NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[person1, person2, person3] copyItems:YES]; //初始化只做一次拷貝基矮,會觸發(fā) Person 的 copy 方法
NSMutableArray *copyArray = [array copy]; //__NSArrayI
NSMutableArray *mutableCopyArray = [array mutableCopy]; //__NSArrayM
NSLog(@"array(%@<%p>: %p): %@", [array class], &array, array, array);
NSLog(@"copyArray(%@<%p>: %p): %@", [copyArray class], ©Array, copyArray, copyArray);
NSLog(@"mutableCopyArray(%@<%p>: %p): %@", [mutableCopyArray class], &mutableCopyArray, mutableCopyArray, mutableCopyArray);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:41:31.266514+0800 TestCocoOC[9649:625978] array(__NSArrayM<0x7ffeef613090>: 0x6040002440b0): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.266738+0800 TestCocoOC[9649:625978] copyArray(__NSArrayI<0x7ffeef613088>: 0x604000243d20): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.267018+0800 TestCocoOC[9649:625978] mutableCopyArray(__NSArrayM<0x7ffeef613080>: 0x604000242820): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.267208+0800 TestCocoOC[9649:625978] end
Class Clusters 分析:
-
__NSArrayI
是不可變數(shù)組子類,可看作NSArray
冠场。 -
__NSArrayM
是可變數(shù)組子類家浇,通常可看作NSMutableArray
碴裙。
根據(jù)以上測試代碼和打印的結(jié)果顯示钢悲,可進(jìn)行以下分析:
- 變量
array
、copyArray
和mutableCopyArray
打印出來的地址是不相同的舔株,說明都是容器的深拷貝莺琳。 - 數(shù)組里的元素打印的對象地址都是一樣的。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSMutableArray | copy | YES | NSArray | NO | NO | 深拷貝 | NO |
mutableCopy | YES | NSMutableArray | NO | NO | 深拷貝 | NO |
NSDictionary
key-value
其實(shí)就是 Hash 表载慈,里面的 key
都是字符串常量惭等。當(dāng)然,拷貝操作也不會對元素做處理办铡。驗(yàn)證拷貝特性的測試代碼如下:
Person *person = [[Person alloc] init];
NSDictionary *dict = @{@"key":@"qwe",
@"num":@1,
@"person": person}; //__NSDictionaryI
NSDictionary *copyDict = [dict copy]; //__NSDictionaryI
NSDictionary *mutableCopyDict = [dict mutableCopy]; //__NSDictionaryM
NSLog(@"dict(%@<%p>: %p): %@", [dict class], &dict, dict, dict);
NSLog(@"copyDict(%@<%p>: %p): %@", [copyDict class], ©Dict, copyDict, copyDict);
NSLog(@"mutableCopyDict(%@<%p>: %p): %@", [mutableCopyDict class], &mutableCopyDict, mutableCopyDict, mutableCopyDict);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:41:48.389669+0800 TestCocoOC[9649:625978] dict(__NSDictionaryI<0x7ffeef613088>: 0x6000000730c0): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.389843+0800 TestCocoOC[9649:625978] copyDict(__NSDictionaryI<0x7ffeef613080>: 0x6000000730c0): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.390006+0800 TestCocoOC[9649:625978] mutableCopyDict(__NSDictionaryM<0x7ffeef613078>: 0x600000036900): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.390375+0800 TestCocoOC[9649:625978] end
Class Clusters 分析:
-
__NSDictionaryI
是不可變字典子類辞做,可看作NSDictionary
。 -
__NSDictionaryM
是可變字典子類寡具,通吵用可看作NSMutableDictionary
。
根據(jù)以上測試代碼和打印的結(jié)果顯示童叠,可進(jìn)行以下分析:
- 變量
dict
和copyDict
打印出來的地址是相同的框喳,都是0x6000000730c0
而且類名相同,都是__NSDictionaryI
,說明只是淺拷貝帖努,而且是NSDictionary
撰豺。 - 變量
mutableCopyDict
打印出的類名__NSDictionaryM
粪般,所以是NSMutableDictionary
拼余。 - 打印出來的元素對象(Person)地址都是一樣的。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSDictionary | copy | NO | NSDictionary | NO | NO | 淺拷貝 | NO |
mutableCopy | YES | NSMutableDictionary | NO | NO | 深拷貝 | NO |
NSMutableDictionary
可變字典類的驗(yàn)證拷貝操作的測試代碼如下:
Person *person = [[Person alloc] init];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"key":@"qwe",
@"num":@1,
@"person": person}]; // __NSDictionaryM
NSMutableDictionary *copyDict = [dict copy]; //__NSFrozenDictionaryM
NSMutableDictionary *mutableCopyDict = [dict mutableCopy]; //__NSDictionaryM
NSLog(@"dict(%@<%p>: %p): %@", [dict class], &dict, dict, dict);
NSLog(@"copyDict(%@<%p>: %p): %@", [copyDict class], ©Dict, copyDict, copyDict);
NSLog(@"mutableCopyDict(%@<%p>: %p): %@", [mutableCopyDict class], &mutableCopyDict, mutableCopyDict, mutableCopyDict);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:42:18.754223+0800 TestCocoOC[9649:625978] dict(__NSDictionaryM<0x7ffeef613088>: 0x604000039040): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754484+0800 TestCocoOC[9649:625978] copyDict(__NSFrozenDictionaryM<0x7ffeef613080>: 0x6040000392c0): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754631+0800 TestCocoOC[9649:625978] mutableCopyDict(__NSDictionaryM<0x7ffeef613078>: 0x604000039400): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754877+0800 TestCocoOC[9649:625978] end
Class Clusters 分析:
-
__NSDictionaryI
是不可變字典子類亩歹,可看作NSDictionary
匙监。 -
__NSFrozenDictionaryM
是可變字典類的副本類,可看作NSDictionary
小作。 -
__NSDictionaryM
是可變字典子類亭姥,通常可看作NSMutableDictionary
顾稀。
根據(jù)以上測試代碼和打印的結(jié)果顯示达罗,可進(jìn)行以下分析:
- 變量
dict
、copyDict
和mutableCopyDict
打印出來的地址是不相同的静秆,說明都是容器的深拷貝粮揉。 - 打印出來的元素對象(Person)地址都是一樣的。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSMutableDictionary | copy | YES | NSDictionary | NO | NO | 深拷貝 | NO |
mutableCopy | YES | NSMutableDictionary | NO | NO | 深拷貝 | NO |
NSSet
不可變?nèi)ブ責(zé)o序集合抚笔,里面的元素都是唯一的扶认。驗(yàn)證拷貝操作的測試代碼如下:
Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSSet *set = [[NSSet alloc] initWithArray:@[person1, person2, person3]]; // __NSSetI
NSSet *copySet = [set copy]; //__NSSetI
NSSet *mutableCopySet = [set mutableCopy]; //__NSSetM
NSLog(@"set(%@<%p>: %p): %@", [set class], &set, set, set);
NSLog(@"copySet(%@<%p>: %p): %@", [copySet class], ©Set, copySet, copySet);
NSLog(@"mutableCopySet(%@<%p>: %p): %@", [mutableCopySet class], &mutableCopySet, mutableCopySet, mutableCopySet);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:43:29.316827+0800 TestCocoOC[9813:648649] set(__NSSetI<0x7ffee4e07090>: 0x60400024d5c0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.316999+0800 TestCocoOC[9813:648649] copySet(__NSSetI<0x7ffee4e07088>: 0x60400024d5c0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.317350+0800 TestCocoOC[9813:648649] mutableCopySet(__NSSetM<0x7ffee4e07080>: 0x60400003b0e0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.317455+0800 TestCocoOC[9813:648649] end
Class Clusters 分析:
-
__NSSetI
是不可變?nèi)ブ責(zé)o序集合子類,可看作NSSet
殊橙。 -
__NSSetM
是可變?nèi)ブ責(zé)o序集合子類辐宾,通常可看作NSMutableSet
膨蛮。
根據(jù)以上測試代碼和打印的結(jié)果顯示叠纹,可進(jìn)行以下分析:
- 變量
set
和copySet
打印出來的地址是相同的,都是0x60400024d5c0
而且類名相同敞葛,都是__NSSetI
誉察,說明只是淺拷貝,而且是NSSet
制肮。 - 變量
mutableCopySet
打印出的類名__NSSetM
冒窍,所以是NSMutableSet
。 - 打印出來的元素對象(Person)地址都是一樣的豺鼻。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSSet | copy | NO | NSSet | NO | NO | 淺拷貝 | NO |
mutableCopy | YES | NSMutableSet | NO | NO | 深拷貝 | NO |
NSMutableSet
可變?nèi)ブ責(zé)o序集合综液,里面的元素都是唯一的。驗(yàn)證拷貝操作的測試代碼如下:
Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSMutableSet *set = [[NSMutableSet alloc] initWithArray:@[person1, person2, person3]]; // __NSSetM
NSMutableSet *copySet = [set copy]; //__NSSetI
NSMutableSet *mutableCopySet = [set mutableCopy]; //__NSSetM
NSLog(@"set(%@<%p>: %p): %@", [set class], &set, set, set);
NSLog(@"copySet(%@<%p>: %p): %@", [copySet class], ©Set, copySet, copySet);
NSLog(@"mutableCopySet(%@<%p>: %p): %@", [mutableCopySet class], &mutableCopySet, mutableCopySet, mutableCopySet);
NSLog(@"end");
打印的結(jié)果如下:
2018-08-17 13:43:52.278444+0800 TestCocoOC[9813:648649] set(__NSSetM<0x7ffee4e07090>: 0x60400003b360): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.278611+0800 TestCocoOC[9813:648649] copySet(__NSSetI<0x7ffee4e07088>: 0x60400024dd10): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.278686+0800 TestCocoOC[9813:648649] mutableCopySet(__NSSetM<0x7ffee4e07080>: 0x60400003b140): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.279086+0800 TestCocoOC[9813:648649] end
Class Clusters 分析:
-
__NSSetI
是不可變?nèi)ブ責(zé)o序集合子類儒飒,可看作NSSet
谬莹。 -
__NSSetM
是可變?nèi)ブ責(zé)o序集合子類,通常可看作NSMutableSet
附帽。
根據(jù)以上測試代碼和打印的結(jié)果顯示埠戳,可進(jìn)行以下分析:
- 變量
set
、copySet
和mutableCopySet
打印出來的地址是不相同的蕉扮,說明都是容器的深拷貝整胃。 - 數(shù)組里的元素打印的對象地址都是一樣的。
根據(jù)以上驗(yàn)證可總結(jié)以下結(jié)果:
類名 | 操作 | 新對象 | 新類名 | 新元素對象 | 調(diào)用舊元素對應(yīng)的Copy方法 | 拷貝類型 | 元素拷貝 |
---|---|---|---|---|---|---|---|
NSMutableSet | copy | YES | NSSet | NO | NO | 深拷貝 | NO |
mutableCopy | YES | NSMutableSet | NO | NO | 深拷貝 | NO |
結(jié)論分析
上一節(jié)的驗(yàn)證結(jié)果符合結(jié)論概括所描述的喳钟。雖然驗(yàn)證過程輸出的類比較復(fù)雜屁使,Apple 引進(jìn)了 Class Clusters
和 Tagged Pointer
的設(shè)計思想,但是還是這不妨礙拷貝操作的總結(jié)奔则。不過有時間的話還是研究一下這兩個設(shè)計思想蛮寂,對以后設(shè)計架構(gòu)會大有進(jìn)步。
根據(jù)這篇文章的結(jié)論概括易茬,在日常開發(fā)中可注意以下幾點(diǎn):
- Objective-C 類中的屬性酬蹋,
NSMutable
開頭的可變集合類屬性不要用copy
關(guān)鍵字去修飾,以為每次賦值操作拷貝出來的都是不可變集合類了抽莱。 -
Collection
類copy
和mutableCopy
方法范抓,集合里面的元素對象都不會發(fā)生拷貝操作。簡單的來說岸蜗,只是對容器操作尉咕。 - 自定義類的拷貝操作是自己控制的。