2019 面試前的準(zhǔn)備 -- Copy

個(gè)人的面試總結(jié)

第一不管面聊還是筆試都少不了的一個(gè)問(wèn)題

一、深拷貝與淺拷貝

淺拷貝

淺拷貝就是對(duì)內(nèi)存地址的復(fù)制,
讓目標(biāo)對(duì)象指針和源對(duì)象指向同一片內(nèi)存空間,就是A和B都指向一個(gè)內(nèi)存地址
當(dāng)內(nèi)存銷(xiāo)毀的時(shí)候,指向這片內(nèi)存的幾個(gè)指針需要重新定義才可以使用,
要不然會(huì)成為野指針。

淺拷貝就是拷貝指向原來(lái)對(duì)象的指針,使原對(duì)象的引用計(jì)數(shù)+1,可以理解為創(chuàng)建了一個(gè)指向原對(duì)象的新指針而已,并沒(méi)有創(chuàng)建一個(gè)全新的對(duì)象。


深拷貝

深拷貝是指拷貝對(duì)象的具體內(nèi)容,而內(nèi)存地址是自主分配的,拷貝結(jié)束之后,
兩個(gè)對(duì)象雖然存的值是相同的,但是內(nèi)存地址不一樣,兩個(gè)對(duì)象也互不影響,互不干涉。
A是A , B是B。

深拷貝就是拷貝出和原來(lái)僅僅是值一樣,但是內(nèi)存地址完全不一樣的新的對(duì)象,創(chuàng)建后和原對(duì)象沒(méi)有任何關(guān)系。


總結(jié)

深拷貝就是內(nèi)容拷貝,淺拷貝就是指針拷貝。本質(zhì)區(qū)別在于:

  • 是否開(kāi)啟新的內(nèi)存地址
  • 是否影響內(nèi)存地址的引用計(jì)數(shù)

分析
  • 非集合對(duì)象的copy和mutableCopy
    不可變對(duì)象的 NSString
    NSString *str1 = @"001";
    NSMutableString *str2 = [str1 copy];
    //copy返回的是不可變對(duì)象,str2不能被修改,因此會(huì)發(fā)生崩潰
//    [str2 appendString:@"test"];
    
    NSMutableString *str3 = [str1 mutableCopy];
    [str3 appendString:@"modify"];
    
    NSLog(@"str1:%p - %@ \r\n",str1,str1);
    NSLog(@"str2:%p - %@ \r\n",str2,str2);
    NSLog(@"str3:%p - %@ \r\n",str3,str3);

打印結(jié)果如下:

    Demo[18677:1838201] str1:0x104dace08 - 001
    Demo[18677:1838201] str2:0x104dace08 - 001
    Demo[18677:1838201] str3:0x600003271440 - 001modify

結(jié)論:

str1、str2地址相同并且與str3地址不同,
NSString的copy是淺拷貝,
且copy返回的對(duì)象是不可變對(duì)象;
mutableCopy是深拷貝。


可變對(duì)象的NSMutableString


    NSMutableString *mstr1 = [NSMutableString stringWithString:@"002"];
    NSMutableString *mstr2 = [mstr1 copy];
    //copy返回的是不可變對(duì)象,mstr2不能被修改,因此會(huì)發(fā)生崩潰
    //[str2 appendString:@"test"];
    
    NSMutableString *mstr3 = [mstr1 mutableCopy];
    [mstr3 appendString:@"modify"];
    
    NSLog(@"mstr1:%p - %@ \r\n",mstr1,mstr1);
    NSLog(@"mstr2:%p - %@ \r\n",mstr2,mstr2);
    NSLog(@"mstr3:%p - %@ \r\n",mstr3,mstr3);

打印結(jié)果如下:

    Demo[18757:1866812] mstr1:0x60000018cc60 - 002
    Demo[18757:1866812] mstr2:0xac293f53799abe6a - 002
    Demo[18757:1866812] mstr3:0x6000001c0480 - 002modify

結(jié)論:

str1、str2地址相同并且與str3地址不同,
NSString的copy是淺拷貝,
且copy返回的對(duì)象是不可變對(duì)象;
mutableCopy是深拷貝。


  • 集合對(duì)象的copy和mutableCopy
    不可變對(duì)象的NSArray
    NSArray *arry1 = [[NSArray alloc] initWithObjects:@"value1", @"value2",nil];
    NSArray *arry2 = [arry1 copy];
    NSArray *arry3 = [arry1 mutableCopy];
    
    NSLog(@"arry1:%p - %@ \r\n",arry1,arry1);
    NSLog(@"arry2:%p - %@ \r\n",arry2,arry2);
    NSLog(@"arry3:%p - %@ \r\n",arry3,arry3);

打印結(jié)果如下:

    Demo[18824:1887493] arry1:0x6000023df060 - (
    value1,
    value2
    )
    Demo[18824:1887493] arry2:0x6000023df060 - (
    value1,
    value2
    )
    Demo[18824:1887493] arry3:0x600002db80f0 - (
    value1,
    value2
    )

結(jié)論:

arry1、arry2 地址一樣,arr3 地址不一樣,
NSArray的copy是淺拷貝,
且copy返回的對(duì)象是不可變對(duì)象;
mutableCopy是深拷貝。


可變對(duì)象NSMutableArray

    NSMutableArray *marry1 = [[NSMutableArray alloc] initWithObjects:@"value1", @"value2",nil];
    NSMutableArray *marry2 = [marry1 copy];
    
    //copy返回的是不可變對(duì)象,marry2不能被修改,因此會(huì)崩潰
    //[marry2 addObject:@"value3"];
    
    NSMutableArray *marry3 = [marry1 mutableCopy];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);

打印結(jié)果如下:

    Demo[18942:1913212] marry1:0x6000004513b0 - (
    mvalue1,
    mvalue2
    )
    Demo[18942:1913212] marry2:0x600000a52be0 - (
    mvalue1,
    mvalue2
    )
    Demo[18942:1913212] marry3:0x6000004507b0 - (
    mvalue1,
    mvalue2
    )

結(jié)論:

marry1、marry2、marr3 地址都不一樣,
NSMutableArray對(duì)象copy與mutableCopy都是深拷貝,
且copy返回的對(duì)象是不可變對(duì)象。


特別注意的是:

對(duì)于集合類(lèi)的可變對(duì)象來(lái)說(shuō),深拷貝并非嚴(yán)格意義上的深復(fù)制,只能算是單層深復(fù)制,即雖然新開(kāi)辟了內(nèi)存地址,但是存放在內(nèi)存上的值(也就是數(shù)組里的元素仍然之鄉(xiāng)員數(shù)組元素值,并沒(méi)有另外復(fù)制一份),這就叫做單層深復(fù)制。

舉例說(shuō)明:


    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc] initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSMutableArray *marry2 = [marry1 copy]; /// copy 返回的是不可變對(duì)象
    NSMutableArray *marry3 = [marry1 mutableCopy];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
    
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);
//    結(jié)果數(shù)組元素地址都是相同的
    
    NSLog(@"\r\n------------------修改原值后------------------------\r\n");
    [mstr1 appendFormat:@"aaa"];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
    NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);

打印結(jié)果如下:


    Demo[19302:1987051] marry1:0x60000259f090 - (
                                                 value1,
                                                 value2
                                                 )
    Demo[19302:1987051] marry2:0x600002b9cfc0 - (
                                                 value1,
                                                 value2
                                                 )
    Demo[19302:1987051] marry3:0x60000259e910 - (
                                                 value1,
                                                 value2
                                                 )
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750
    
    Demo[19302:1987051]
    ------------------修改原值后------------------------
    
    Demo[19302:1987051] marry1:0x60000259f090 - (
                                                 value1aaa,
                                                 value2
                                                 )
    Demo[19302:1987051] marry2:0x600002b9cfc0 - (
                                                 value1aaa,
                                                 value2
                                                 )
    Demo[19302:1987051] marry3:0x60000259e910 - (
                                                 value1aaa,
                                                 value2
                                                 )
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750
    Demo[19302:1987051] 數(shù)組元素地址:value1:0x60000259f180 - value2:0x60000259f750

結(jié)論:

在修改原值之前,marry1、marry2、marr3 地址都不一樣,很明顯copy和mutableCopy都是深拷貝,但是從修改原值后的打印結(jié)果來(lái)看,這里的深拷貝只是單層深拷貝:新開(kāi)辟了內(nèi)存地址,但是數(shù)組中的值還是指向原數(shù)組的,這樣才能在修改原值后,marry2 marr3中的值都修改了。另外,從打印的數(shù)組元素地址可以很明顯的看出來(lái),修改前后marry1、marry、marr3的數(shù)組元素地址都是一模一樣的。

可以用歸檔做成完全的深拷貝
代碼如下:

    NSMutableArray *marry1 = [[NSMutableArray alloc] init];
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
    
    [marry1 addObject:mstr1];
    [marry1 addObject:mstr2];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];
    NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
    
    NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
    NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
    NSLog(@"數(shù)組元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);

打印結(jié)果:

    Demo[19560:2037523] marry1:0x600001f26400 - (
     value1,
     value2
     )
    Demo[19560:2037523] marry2:0x600001f39a10 - (
     value1,
     value2
     )
    Demo[19560:2037523] 數(shù)組元素地址:value1:0x600001f264c0 - value2:0x600001f26520
    Demo[19560:2037523] 數(shù)組元素地址:value1:0x600001f399b0 - value2:0x600001f39a40

結(jié)論:
我們可以看到,開(kāi)辟了新的內(nèi)存地址的同時(shí),
數(shù)組元素的指針地址也不同了,實(shí)現(xiàn)了完全的深拷貝。


準(zhǔn)則

  • 可變對(duì)象的copy和mutableCopy方法都是深拷貝(區(qū)別完全深拷貝與單層深拷貝)。
  • 不可變對(duì)象的copy方法是淺拷貝,mutableCopy方法是深拷貝。
  • copy方法返回的對(duì)象都是不可變對(duì)象。

面試的時(shí)候把這些說(shuō)出來(lái)copy絕對(duì)沒(méi)有問(wèn)題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,674評(píng)論 1 32
  • 1.設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式,并簡(jiǎn)要敘述?設(shè)計(jì)模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類(lèi)型...
    龍飝閱讀 2,303評(píng)論 0 12
  • 前言 不敢說(shuō)覆蓋OC中所有copy的知識(shí)點(diǎn),但最起碼是目前最全的最新的一篇關(guān)于 copy的技術(shù)文檔了。后續(xù)發(fā)現(xiàn)有新...
    zyydeveloper閱讀 3,721評(píng)論 4 35
  • 如果不拖,我們本可以有個(gè)很好的周末; 如果不拖,我們本可以早早的享受一天的美好; 如果不拖,我們本可以擊退一天的陰...
    豪仔_Matrix閱讀 660評(píng)論 0 0
  • 前面188日志記錄的那件事后,我也沒(méi)跟那個(gè)隊(duì)員說(shuō)話,好轉(zhuǎn)的一面是我不怪罪他,也不去討好他,一切順其自然。 昨天沒(méi)想...
    思言悟語(yǔ)閱讀 119評(píng)論 0 1

友情鏈接更多精彩內(nèi)容