OC對象中copy和mutableCopy方法詳解

前言

前段時間射亏,看到在知識小集的交流群里正在討論 copymutableCopy 這兩個方法的相關(guān)特性琢唾。而這兩個方法的使用寡壮,對于 Collection 來說咳促,確實(shí)在運(yùn)行的時候會有些不一樣。主要還是為了記錄一下襟沮,避免以后忘記锥惋,所以寫了這篇文章。

理論概述

本文章將會討論 CoreFoundationFoundation 框架里面的 Collection 類,當(dāng)然也會簡單的講述自己定義的類,怎么實(shí)現(xiàn) copymutableCopy 方法菇夸。

Collection 類的結(jié)論概括

首先铁孵,先查看有關(guān) Collection 類的總結(jié)。當(dāng)然,以下表格總結(jié)的結(jié)論只驗(yàn)證過一下這些類 NSStringNSMutableStringNSArray丛忆、NSMutableArrayNSDictionary仍秤、NSMutableDictionary熄诡、NSSetNSMutableSet

類名 操作 新對象 新類名 新元素對象 調(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é)論:

  1. Collection 類(容器)所有的 Copy 操作都只是對容器操作诗力,不會對容器里的元素進(jìn)行 Copy 操作凰浮。

  2. 只有 NS 開頭的不可變字符串/數(shù)組/字典等集合類型調(diào)用 copy 方法才是淺拷貝(指針拷貝),不會生成新容器對象苇本;其余的情況袜茧,則是深拷貝(內(nèi)容拷貝),會生成對應(yīng)的新容器對象瓣窄,但容器內(nèi)的元素還是原來的元素笛厦。

  3. 調(diào)用 copy 方法輸出的是 NS 開頭的不可變字符串/數(shù)組/字典等集合類型,調(diào)用 mutableCopy 方法輸出的是 NSMutable 開頭的可變字符串/數(shù)組/字典等集合類型(這里說的是輸出的類型俺夕,不一定產(chǎn)生新容器對象)裳凸。

自定義類的結(jié)論概括

自定義類,調(diào)用 copymutableCopy 方法的輸出規(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)用 copymutableCopy 的情況守谓。運(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], &copyStr, 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 分析:

  1. __NSCFConstantString 是字符串常量類,可看作 NSString您单。
  2. __NSCFString 是字符串類斋荞,通常可看作 NSMutableString虐秦。

根據(jù)以上測試代碼和打印的結(jié)果顯示平酿,可進(jìn)行以下分析:

  1. 變量 strcopyStr 打印出來的地址是相同的,都是 0x106529148而且類名相同悦陋,都是 __NSCFConstantString蜈彼,說明只是淺拷貝,而且是 NSString俺驶。
  2. 變量 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

可變字符串copymutableCopy操作,測試代碼如下:

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], &copyStr, 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 分析:

  1. NSTaggedPointerString 是字符串常量類送矩,可看作 NSString蚕甥,這個類具備 Tagged Pointer 特性。
  2. __NSCFString 是字符串類栋荸,通彻交常可看作 NSMutableString

根據(jù)打印的結(jié)果可得出以下分析:

  1. str晌块、copyStrmutableCopyStr 指針指向的地址都是不一樣的爱沟,說明都生成了新對象。
  2. 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], &copyArray, 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 分析:

  1. __NSArrayI 是不可變數(shù)組子類搂根,可看作 NSArray
  2. __NSArrayM 是可變數(shù)組子類铃辖,通呈@ⅲ可看作 NSMutableArray

根據(jù)以上測試代碼和打印的結(jié)果顯示娇斩,可進(jìn)行以下分析:

  1. 變量 arraycopyArray 打印出來的地址是相同的仁卷,都是 0x60c00024c3f0而且類名相同,都是 __NSArrayI犬第,說明只是淺拷貝锦积,而且是 NSArray
  2. 變量 mutableCopyStr 打印出的類名 __NSArrayM瓶殃,所以是 NSMutableArray充包。
  3. 數(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], &copyArray, 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 分析:

  1. __NSArrayI 是不可變數(shù)組子類,可看作 NSArray冠场。
  2. __NSArrayM 是可變數(shù)組子類家浇,通常可看作 NSMutableArray碴裙。

根據(jù)以上測試代碼和打印的結(jié)果顯示钢悲,可進(jìn)行以下分析:

  1. 變量 arraycopyArraymutableCopyArray 打印出來的地址是不相同的舔株,說明都是容器的深拷貝莺琳。
  2. 數(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], &copyDict, 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 分析:

  1. __NSDictionaryI 是不可變字典子類辞做,可看作 NSDictionary
  2. __NSDictionaryM 是可變字典子類寡具,通吵用可看作 NSMutableDictionary

根據(jù)以上測試代碼和打印的結(jié)果顯示童叠,可進(jìn)行以下分析:

  1. 變量 dictcopyDict 打印出來的地址是相同的框喳,都是 0x6000000730c0而且類名相同,都是 __NSDictionaryI,說明只是淺拷貝帖努,而且是 NSDictionary撰豺。
  2. 變量 mutableCopyDict 打印出的類名 __NSDictionaryM粪般,所以是 NSMutableDictionary拼余。
  3. 打印出來的元素對象(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], &copyDict, 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 分析:

  1. __NSDictionaryI 是不可變字典子類亩歹,可看作 NSDictionary匙监。
  2. __NSFrozenDictionaryM可變字典類的副本類,可看作 NSDictionary小作。
  3. __NSDictionaryM 是可變字典子類亭姥,通常可看作 NSMutableDictionary顾稀。

根據(jù)以上測試代碼和打印的結(jié)果顯示达罗,可進(jìn)行以下分析:

  1. 變量 dictcopyDictmutableCopyDict 打印出來的地址是不相同的静秆,說明都是容器的深拷貝粮揉。
  2. 打印出來的元素對象(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], &copySet, 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 分析:

  1. __NSSetI 是不可變?nèi)ブ責(zé)o序集合子類,可看作 NSSet殊橙。
  2. __NSSetM 是可變?nèi)ブ責(zé)o序集合子類辐宾,通常可看作 NSMutableSet膨蛮。

根據(jù)以上測試代碼和打印的結(jié)果顯示叠纹,可進(jìn)行以下分析:

  1. 變量 setcopySet 打印出來的地址是相同的,都是 0x60400024d5c0而且類名相同敞葛,都是 __NSSetI誉察,說明只是淺拷貝,而且是 NSSet制肮。
  2. 變量 mutableCopySet 打印出的類名 __NSSetM冒窍,所以是 NSMutableSet
  3. 打印出來的元素對象(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], &copySet, 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 分析:

  1. __NSSetI 是不可變?nèi)ブ責(zé)o序集合子類儒飒,可看作 NSSet谬莹。
  2. __NSSetM 是可變?nèi)ブ責(zé)o序集合子類,通常可看作 NSMutableSet附帽。

根據(jù)以上測試代碼和打印的結(jié)果顯示埠戳,可進(jìn)行以下分析:

  1. 變量 setcopySetmutableCopySet 打印出來的地址是不相同的蕉扮,說明都是容器的深拷貝整胃。
  2. 數(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 ClustersTagged Pointer 的設(shè)計思想,但是還是這不妨礙拷貝操作的總結(jié)奔则。不過有時間的話還是研究一下這兩個設(shè)計思想蛮寂,對以后設(shè)計架構(gòu)會大有進(jìn)步。
根據(jù)這篇文章的結(jié)論概括易茬,在日常開發(fā)中可注意以下幾點(diǎn):

  1. Objective-C 類中的屬性酬蹋,NSMutable 開頭的可變集合類屬性不要用 copy 關(guān)鍵字去修飾,以為每次賦值操作拷貝出來的都是不可變集合類了抽莱。
  2. CollectioncopymutableCopy 方法范抓,集合里面的元素對象都不會發(fā)生拷貝操作。簡單的來說岸蜗,只是對容器操作尉咕。
  3. 自定義類的拷貝操作是自己控制的。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末璃岳,一起剝皮案震驚了整個濱河市年缎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铃慷,老刑警劉巖单芜,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異犁柜,居然都是意外死亡洲鸠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門馋缅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扒腕,“玉大人,你說我怎么就攤上這事萤悴●” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵覆履,是天一觀的道長蹋盆。 經(jīng)常有香客問我费薄,道長,這世上最難降的妖魔是什么栖雾? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任楞抡,我火速辦了婚禮,結(jié)果婚禮上析藕,老公的妹妹穿的比我還像新娘召廷。我一直安慰自己,他們只是感情好噪径,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布柱恤。 她就那樣靜靜地躺著,像睡著了一般找爱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泡孩,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天车摄,我揣著相機(jī)與錄音,去河邊找鬼仑鸥。 笑死吮播,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的眼俊。 我是一名探鬼主播意狠,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疮胖!你這毒婦竟也來了环戈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤澎灸,失蹤者是張志新(化名)和其女友劉穎院塞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體性昭,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拦止,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了糜颠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汹族。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖其兴,靈堂內(nèi)的尸體忽然破棺而出顶瞒,到底是詐尸還是另有隱情,我是刑警寧澤忌警,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布搁拙,位于F島的核電站秒梳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏箕速。R本人自食惡果不足惜酪碘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盐茎。 院中可真熱鬧兴垦,春花似錦、人聲如沸字柠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窑业。三九已至钦幔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間常柄,已是汗流浹背鲤氢。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留西潘,地道東北人卷玉。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像喷市,于是被迫代替她去往敵國和親相种。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容