iOS:深拷貝和淺拷貝

淺拷貝
對(duì)內(nèi)存地址的復(fù)制,沒有對(duì)內(nèi)存空間復(fù)制翁狐,讓目標(biāo)對(duì)象指針和源對(duì)象指向同一塊內(nèi)存空間类溢。
增加被拷貝對(duì)象引用計(jì)數(shù),未發(fā)生新的內(nèi)存分配露懒。

深拷貝
讓目標(biāo)對(duì)象和源對(duì)象指針分別指向內(nèi)容相同的內(nèi)存空間闯冷。
不會(huì)增加被拷貝對(duì)象的引用計(jì)數(shù),產(chǎn)生新的內(nèi)存分配隐锭。

1窃躲、非容器對(duì)象的深拷貝和淺拷貝
以NSString 和 NSMutableString為例

    NSString *str1 = @"str1";
    NSString *str1Copy = [str1 copy];
    NSString *str1mutCopy = [str1 mutableCopy];
    NSMutableString *mutstr1Copy = [str1 copy];
    NSMutableString *mutstr1mutCopy = [str1 mutableCopy];
    NSLog(@"str1 = %@, address = %p",str1,str1);
    NSLog(@"str1Copy = %@, address = %p",str1Copy,str1Copy);
    NSLog(@"str1mutCopy = %@, address = %p",str1mutCopy,str1mutCopy);
    NSLog(@"mutstr1Copy = %@, address = %p",mutstr1Copy,mutstr1Copy);
    NSLog(@"mutstr1mutCopy = %@, address = %p",mutstr1mutCopy,mutstr1mutCopy);

    NSMutableString *mutstr2 = [NSMutableString stringWithString:@"mutstrhello2"];
    NSMutableString *mutstr2Copy = [mutstr2 copy];
    NSMutableString *mutstr2mutCopy = [mutstr2 mutableCopy];
    NSString *str2Copy = [mutstr2 copy];
    NSString *str2mutCopy = [mutstr2 mutableCopy];
    NSLog(@"mutstr2 = %@, address = %p",mutstr2,mutstr2);
    NSLog(@"mutstr2Copy = %@, address = %p",mutstr2Copy,mutstr2Copy);
    NSLog(@"mutstr2mutCopy = %@, address = %p",mutstr2mutCopy,mutstr2mutCopy);
    NSLog(@"str2Copy = %@, address = %p",str2Copy,str2Copy);
    NSLog(@"str2mutCopy = %@, address = %p",str2mutCopy,str2mutCopy);

輸出結(jié)果
str1 = str1, address = 0x10c44f2e8
str1Copy = str1, address = 0x10c44f2e8
str1mutCopy = str1, address = 0x6000025d2a30
mutstr1Copy = str1, address = 0x10c44f2e8
mutstr1mutCopy = str1, address = 0x6000025d2a60

mutstr2 = mutstrhello2, address = 0x6000025e84b0
mutstr2Copy = mutstrhello2, address = 0x600002b95000
mutstr2mutCopy = mutstrhello2, address = 0x6000025e8300
str2Copy = mutstrhello2, address = 0x600002b94f80
str2mutCopy = mutstrhello2, address = 0x6000025e82d0

可以看到結(jié)論如下:

可變對(duì)象copy/mutablecopy都是深拷貝。
不可變對(duì)象的copy是淺拷貝钦睡。
??????copy方法返回的都是不可變對(duì)象蒂窒,可變對(duì)象經(jīng)過copy后不可變。

2荞怒、自定義類對(duì)象的深淺拷貝
必須實(shí)現(xiàn)NSCopying協(xié)議

@interface TestModel : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSMutableString *mutname;
@end

@implementation TestModel
- (id)copyWithZone:(NSZone *)zone {
    TestModel *t = [[TestModel allocWithZone:zone]init];
    t.name = self.name;
    t.mutname = self.mutname;
    return t;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    TestModel *t = [[TestModel allocWithZone:zone]init];
    t.name = self.name;
    t.mutname = self.mutname;
    return t;
}
@end
   TestModel *t1 = [[TestModel alloc]init];
    t1.name = @"test1";
    t1.mutname = [NSMutableString stringWithString:@"mut111"];
    TestModel *t1Copy = [t1 copy];
    TestModel *t1Mutcopy = [t1 mutableCopy];

    NSLog(@"t1 = %p, t1.name = %p,t1.mutname = %p",t1, t1.name,t1.mutname);
    NSLog(@"t1Copy = %p, t1Copy.name = %p,t1Copy.mutname = %p",t1Copy, t1Copy.name,t1Copy.mutname);
    NSLog(@"t1Mutcopy = %p, t1Mutcopy.name = %p,t1Mutcopy.mutname = %p",t1Mutcopy, t1Mutcopy.name,t1Mutcopy.mutname);

輸出
t1 = 0x600002f61940, t1.name = 0x104fc52f0, t1.mutname = 0x600002116250
t1Copy = 0x600002f61980, t1Copy.name = 0x104fc52f0, t1Copy.mutname = 0x600002116250
t1Mutcopy = 0x600002f619a0, t1Mutcopy.name = 0x104fc52f0, t1Mutcopy.mutname = 0x600002116250

實(shí)驗(yàn)可知自定義類的copy和mutablecopy洒琢,都是深拷貝,但是自定義類屬性是淺拷貝褐桌,也就是只是復(fù)制了屬性的引用衰抑,可以和容器類元素一起了解。

2荧嵌、容器類型
以NSArray和NSMutableArray為例

    NSString *tmp = @"str1";
    NSArray *arr1 = @[tmp,@"a",@"b",@"c"];
    NSArray *arr1Copy = [arr1 copy];
    NSArray *arr1Mutcopy = [arr1 mutableCopy];
    NSMutableArray *mutarr1Copy = [arr1 copy];
    NSMutableArray *mutarr1Mutcopy = [arr1 mutableCopy];

    NSLog(@"arr1 = %p, arr1[0] = %p",arr1,arr1[0]);
    NSLog(@"arr1Copy = %p, arr1Copy[0] = %p",arr1Copy,arr1Copy[0]);
    NSLog(@"arr1Mutcopy = %p, arr1Mutcopy[0] = %p",arr1Mutcopy,arr1Mutcopy[0]);
    NSLog(@"mutarr1Copy = %p, mutarr1Copy[0] = %p",mutarr1Copy,mutarr1Copy[0]);
    NSLog(@"mutarr1Mutcopy = %p, mutarr1Mutcopy[0] = %p",mutarr1Mutcopy,mutarr1Mutcopy[0]);

    NSMutableArray *mutarr2 = [NSMutableArray arrayWithObjects:tmp,@"muta",@"mutb",@"mutc", nil];
    NSMutableArray *mutarr2Copy = [mutarr2 copy];
    NSMutableArray *mutarr2Mutcopy = [mutarr2 mutableCopy];
    NSArray *arr2Copy = [arr1 copy];
    NSArray *arr2Mutcopy = [arr1 mutableCopy];

    NSLog(@"mutarr2 = %p, mutarr2[0] = %p",mutarr2,mutarr2[0]);
    NSLog(@"mutarr2Copy = %p, mutarr2Copy[0] = %p",mutarr2Copy,mutarr2Copy[0]);
    NSLog(@"mutarr2Mutcopy = %p, mutarr2Mutcopy[0] = %p",mutarr2Mutcopy,mutarr2Mutcopy[0]);
    NSLog(@"arr2Copy = %p, arr2Copy[0] = %p",arr2Copy,arr2Copy[0]);
    NSLog(@"arr2Mutcopy = %p, arr2Mutcopy[0] = %p",arr2Mutcopy,arr2Mutcopy[0]);

輸出結(jié)果
arr1 = 0x600000870660, arr1[0] = 0x10e7f52f8
arr1Copy = 0x600000870660, arr1Copy[0] = 0x10e7f52f8
arr1Mutcopy = 0x600000870540, arr1Mutcopy[0] = 0x10e7f52f8
mutarr1Copy = 0x600000870660, mutarr1Copy[0] = 0x10e7f52f8
mutarr1Mutcopy = 0x6000008707e0, mutarr1Mutcopy[0] = 0x10e7f52f8

mutarr2 = 0x6000008707b0, mutarr2[0] = 0x10e7f52f8
mutarr2Copy = 0x600000870930, mutarr2Copy[0] = 0x10e7f52f8
mutarr2Mutcopy = 0x6000008705d0, mutarr2Mutcopy[0] = 0x10e7f52f8
arr2Copy = 0x600000870660, arr2Copy[0] = 0x10e7f52f8
arr2Mutcopy = 0x6000008708d0, arr2Mutcopy[0] = 0x10e7f52f8

對(duì)于系統(tǒng)容器(數(shù)組/集合等)而言呛踊,整個(gè)容器符合非容器類深淺拷貝的規(guī)律。
但容器內(nèi)的元素始終是淺拷貝啦撮,容器元素的地址都沒有變化谭网。

數(shù)組中的元素實(shí)際上是對(duì)象的引用,數(shù)組內(nèi)存儲(chǔ)的元素實(shí)際上是指向?qū)ο蟮囊迷叽海皇菍?duì)象本身愉择。當(dāng)我們將一個(gè)對(duì)象添加到數(shù)組中,實(shí)際上是將該對(duì)象的引用存儲(chǔ)在數(shù)組對(duì)應(yīng)的位置上。

示例:

    NSMutableString *str1 = [NSMutableString stringWithString:@"Hello"];
    NSString *str2 = @"oc";
    NSArray *arr = @[str1, str2];
    NSLog(@"arr = %@",arr);
    [str1 appendString:@"123"];
    NSLog(@"new arr = %@",arr);

輸出
arr = (
    Hello,
    oc
)
new arr = (
    Hello123,
    oc
)

??:使用NSMutableString 拼接是為了確保地址不變锥涕,如果是NSString衷戈,重新賦,相當(dāng)于重新初始化层坠,會(huì)生成新的地址殖妇。

3、如何實(shí)現(xiàn)完全深拷貝

1窿春、使用copyItems

    TestModel *t1 = [[TestModel alloc]init];
    t1.name = @"test1";
    NSArray *arr = @[t1];
    NSArray *copyArray = [arr copy];
    NSArray *mutCopyArray = [arr mutableCopy];
    NSArray *newArr = [[NSArray alloc]initWithArray:arr copyItems:YES];

    NSLog(@"arr = %p, arr[0] = %p",arr,arr[0]);
    NSLog(@"copyArray = %p, copyArray[0] = %p",copyArray,copyArray[0]);
    NSLog(@"mutCopyArray = %p, mutCopyArray[0] = %p",mutCopyArray,mutCopyArray[0]);
    NSLog(@"newArr = %p, newArr[0] = %p",newArr,newArr[0]);

輸出
arr = 0x6000020a8270, arr[0] = 0x6000022bf1e0
copyArray = 0x6000020a8270, copyArray[0] = 0x6000022bf1e0
mutCopyArray = 0x600002cf7300, mutCopyArray[0] = 0x6000022bf1e0
newArr = 0x6000020a8250, newArr[0] = 0x6000022bf200

如果容器內(nèi)對(duì)象中的元素是非容器類拉一,可以使用copyItems進(jìn)行完全深拷貝,根據(jù)官方文檔對(duì)copyItems的解釋
copyItems官方文檔

當(dāng)YES時(shí)旧乞,可以使第一層元素實(shí)現(xiàn)深拷貝蔚润,更深層的還是使用對(duì)象的引用。

2尺栖、遞歸復(fù)制屬性

@interface TestModel : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSMutableString *mutname;
@end

@implementation TestModel
- (id)copyWithZone:(NSZone *)zone {
    TestModel *t = [[TestModel allocWithZone:zone]init];
    t.name = [self.name copy];
    t.mutname = [self.mutname mutableCopy];
    return t;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    TestModel *t = [[TestModel allocWithZone:zone]init];
    t.name = [self.name copy];
    t.mutname = [self.mutname mutableCopy];
    return t;
}
@end
    TestModel *t1 = [[TestModel alloc]init];
    t1.name = @"test1";
    t1.mutname = [NSMutableString stringWithString:@"mut111"];
    TestModel *t1Copy = [t1 copy];
    TestModel *t1Mutcopy = [t1 mutableCopy];
    NSLog(@"t1 = %p, t1.name = %p,t1.mutname = %p",t1, t1.name,t1.mutname);
    NSLog(@"t1Copy = %p, t1Copy.name = %p,t1Copy.mutname = %p",t1Copy, t1Copy.name,t1Copy.mutname);
    NSLog(@"t1Mutcopy = %p, t1Mutcopy.name = %p,t1Mutcopy.mutname = %p",t1Mutcopy, t1Mutcopy.name,t1Mutcopy.mutname);

輸出:
t1 = 0x6000019c25c0, t1.name = 0x104ec52f0,t1.mutname = 0x6000017b64c0
t1Copy = 0x6000019c2600, t1Copy.name = 0x104ec52f0,t1Copy.mutname = 0x6000017b6580
t1Mutcopy = 0x6000019c2640, t1Mutcopy.name = 0x104ec52f0,t1Mutcopy.mutname = 0x6000017b63d0 

3嫡纠、解檔歸檔
若是自定義對(duì)象,必須遵循NSCoding協(xié)議

    NSArray *arr = @[@"ceshi shu"];
    NSArray *copyArr = [arr copy];
    NSArray *mutCopyArr = [arr mutableCopy];
    // 使用歸檔和解檔來創(chuàng)建數(shù)組的深拷貝
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
    NSArray *newArr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"arr = %p, arr[0] = %p", arr, arr[0]);
    NSLog(@"copyArr = %p, copyArr[0] = %p", copyArr, copyArr[0]);
    NSLog(@"mutCopyArr = %p, mutCopyArr[0] = %p", mutCopyArr, mutCopyArr[0]);
    NSLog(@"newArr = %p, newArr[0] = %p", newArr, newArr[0]);

輸出:
arr = 0x600000978260, arr[0] = 0x10d44c300
copyArr = 0x600000978260, copyArr[0] = 0x10d44c300
mutCopyArr = 0x600000509b60, mutCopyArr[0] = 0x10d44c300
newArr = 0x6000009782e0, newArr[0] = 0x8b27a7029db7aeb2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末延赌,一起剝皮案震驚了整個(gè)濱河市除盏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挫以,老刑警劉巖者蠕,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掐松,居然都是意外死亡踱侣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門大磺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抡句,“玉大人,你說我怎么就攤上這事杠愧〈疲” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵流济,是天一觀的道長(zhǎng)锐锣。 經(jīng)常有香客問我,道長(zhǎng)绳瘟,這世上最難降的妖魔是什么刺下? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮稽荧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己姨丈,他們只是感情好畅卓,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蟋恬,像睡著了一般翁潘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歼争,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天拜马,我揣著相機(jī)與錄音,去河邊找鬼沐绒。 笑死俩莽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乔遮。 我是一名探鬼主播扮超,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蹋肮!你這毒婦竟也來了出刷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤坯辩,失蹤者是張志新(化名)和其女友劉穎馁龟,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漆魔,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坷檩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厦凤,死狀恐怖袄简,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兼呵,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站涯塔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏清蚀。R本人自食惡果不足惜匕荸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枷邪。 院中可真熱鬧榛搔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至尔觉,卻和暖如春凉袱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侦铜。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工专甩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钉稍。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓涤躲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嫁盲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子篓叶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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