OC之?dāng)?shù)組的copy方法

淺拷貝和深拷貝

蘋(píng)果官方文檔是這樣解釋的

There are two kinds of object copying: shallow copies and deep copies. The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection.

谷歌翻譯

有兩種對(duì)象復(fù)制:淺拷貝和深拷貝。 正常副本是一個(gè)淺拷貝,它產(chǎn)生一個(gè)新集合从绘,它與原始對(duì)象共享對(duì)象的所有權(quán)乾蓬。 深度副本從原始文件創(chuàng)建新對(duì)象篡诽,并將它們添加到新集合厂抖。

更直觀的解釋如下圖:

CopyingCollections_2x.png

NSArray的copy

NSArray內(nèi)部已經(jīng)實(shí)現(xiàn)了NSCopying協(xié)議并蝗,所以可以直接調(diào)用copy方法蝠猬,假如其內(nèi)部沒(méi)實(shí)現(xiàn)的話就需要我們自己實(shí)現(xiàn)- (id)copyWithZone:(NSZone *)zone方法切蟋,否則就會(huì)報(bào)錯(cuò)。NSMutableArray同理榆芦。
而Foundation框架中提供的所有集合默認(rèn)都是淺拷貝柄粹,驗(yàn)證如下

新建Student和Name類,代碼挺簡(jiǎn)單匆绣,就不做解釋了

@interface Name : NSObject<NSCopying>

@property (nonatomic, copy) NSString *surname; // 姓
@property (nonatomic, copy) NSString *firstName; // 名

@end

@implementation Name

- (id)copyWithZone:(NSZone *)zone{
    Name *copy = [[[self class] allocWithZone:zone] init];
    return copy;
}

@end

@interface Student : NSObject<NSCopying>

@property (nonatomic, strong) Name *name;
@property (nonatomic, strong) NSString *address;

@end

@implementation Student

- (instancetype)init {
    self = [super init];
    if (self) {

    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    Student *copy = [[[self class] allocWithZone:zone] init];
    copy.name = [self.name copy];
    return copy;
}
@end

然后驻右,構(gòu)建NSArray,通過(guò)mutableCopy拷貝一份并打印拷貝前后兩者的地址進(jìn)行比較犬绒,代碼如下

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;

    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [studentsArray mutableCopy];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);

打印結(jié)果

studentsArray[0]:0x1002013b0
studentsArrayCopy[0]:0x1002013b0
studentsArrayAddress:0x100203210
studentsArrayCopyAddress:0x100203320

可見(jiàn)studentsArray(原數(shù)據(jù))和studentsArrayCopy(拷貝后的數(shù)據(jù))地址是不同的旺入,而數(shù)組中的元素的地址相同,可見(jiàn)通過(guò)mutableCopy方法實(shí)現(xiàn)的拷貝是淺拷貝凯力。

數(shù)組還提供了一種copy方法茵瘾,- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;,flag表示是否把數(shù)組元素也拷貝一份,如果數(shù)組的元素沒(méi)有實(shí)現(xiàn)NSCopying協(xié)議而且flag設(shè)置成YES的話咐鹤,調(diào)用該方法是會(huì)Crash的拗秘。如果數(shù)組中的所有層級(jí)都實(shí)現(xiàn)了NSCopying方法的話,這種方式的拷貝就是所謂的深拷貝祈惶,即完全復(fù)制一份雕旨。驗(yàn)證如下

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;
    
    
    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [[NSMutableArray alloc] initWithArray:studentsArray copyItems:YES];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);
    
    Name *nameCopy = ((Student *)studentsArrayCopy[0]).name;
    NSLog(@"\nname:%p",name);
    NSLog(@"\nnameCopy:%p",nameCopy);

打印結(jié)果如下

studentsArray[0]:0x100300070
studentsArrayCopy[0]:0x100300930
studentsArrayAddress:0x100300700
studentsArrayCopyAddress:0x100300a00
name:0x100300130
nameCopy:0x1003009e0

所有的原對(duì)象和copy對(duì)象都不同,可見(jiàn)是深拷貝捧请。當(dāng)我們要實(shí)現(xiàn)復(fù)制一個(gè)數(shù)組并在操作之后對(duì)原數(shù)組無(wú)影響的需求時(shí)就可以通過(guò)這種方式凡涩。
當(dāng)然,如果數(shù)組層次很多的話疹蛉,這方式明顯不可取活箕,幸運(yùn)的是蘋(píng)果提供了一種更簡(jiǎn)單的實(shí)現(xiàn)方式(本人沒(méi)驗(yàn)證過(guò))

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

還有,- (instancetype)initWithArray:(NSArray<ObjectType> *)array;這種拷貝方式和- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;方式是一樣的可款,當(dāng)后者的flag設(shè)置成NO的時(shí)候育韩,這兩個(gè)這兩方法是完全相同的克蚂。而且這樣方式和直接調(diào)用copy方式的拷貝也是一樣的

    Student *student = [Student new];
    Name *name = [Name new];
    student.name = name;
    
    
    NSMutableArray *studentsArray = [NSMutableArray new];
    [studentsArray addObject:student];
    NSMutableArray *studentsArrayCopy = [[NSMutableArray alloc] initWithArray:studentsArray copyItems:NO];

    NSLog(@"\nstudentsArray[0]:%p",studentsArray[0]);
    NSLog(@"\nstudentsArrayCopy[0]:%p",studentsArrayCopy[0]);
    NSLog(@"\nstudentsArrayAddress:%p",studentsArray);
    NSLog(@"\nstudentsArrayCopyAddress:%p",studentsArrayCopy);
    
    Name *nameCopy = ((Student *)studentsArrayCopy[0]).name;
    NSLog(@"\nname:%p",name);
    NSLog(@"\nnameCopy:%p",nameCopy);

打印結(jié)果

studentsArray[0]:0x1004041d0
studentsArrayCopy[0]:0x1004041d0
studentsArrayAddress:0x1004060c0
studentsArrayCopyAddress:0x100406260
name:0x100405ef0
nameCopy:0x100405ef0

數(shù)組地址不同,內(nèi)部元素相同筋讨。沒(méi)毛病埃叭。

總結(jié)

  • 淺拷貝:
    1, 直接調(diào)用copy/mutableCopy方法
    2, [[NSMutableArray alloc] initWithArray:studentsArray copyItems:NO]
    3, [[NSMutableArray alloc] initWithArray:studentsArray]
  • 深拷貝:
    1, [[NSMutableArray alloc] initWithArray:studentsArray copyItems:YES],前提要自己實(shí)現(xiàn)每一層級(jí)的NSCopying協(xié)議
    2, [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]]

參考鏈接:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悉罕,隨后出現(xiàn)的幾起案子赤屋,更是在濱河造成了極大的恐慌,老刑警劉巖蛮粮,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件益缎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡然想,警方通過(guò)查閱死者的電腦和手機(jī)莺奔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)变泄,“玉大人令哟,你說(shuō)我怎么就攤上這事》劣迹” “怎么了屏富?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蛙卤。 經(jīng)常有香客問(wèn)我狠半,道長(zhǎng),這世上最難降的妖魔是什么颤难? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任神年,我火速辦了婚禮,結(jié)果婚禮上行嗤,老公的妹妹穿的比我還像新娘已日。我一直安慰自己,他們只是感情好栅屏,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布飘千。 她就那樣靜靜地躺著,像睡著了一般栈雳。 火紅的嫁衣襯著肌膚如雪护奈。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天哥纫,我揣著相機(jī)與錄音逆济,去河邊找鬼。 笑死磺箕,一個(gè)胖子當(dāng)著我的面吹牛奖慌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播松靡,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼简僧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了雕欺?” 一聲冷哼從身側(cè)響起岛马,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屠列,沒(méi)想到半個(gè)月后啦逆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笛洛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年夏志,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苛让。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沟蔑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狱杰,到底是詐尸還是另有隱情瘦材,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布仿畸,位于F島的核電站食棕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏错沽。R本人自食惡果不足惜簿晓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甥捺。 院中可真熱鬧抢蚀,春花似錦、人聲如沸镰禾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吴侦。三九已至屋休,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間备韧,已是汗流浹背劫樟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叠艳。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓奶陈,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親附较。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吃粒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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