多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > iOS開發——深拷貝與淺拷貝詳解

iOS開發——深拷貝與淺拷貝詳解

來源:程序員人生   發布時間:2016-08-24 08:28:08 閱讀次數:2630次

       深拷貝和淺拷貝這個問題在面試中常常被問到,而在實際開發中,只要稍有不慎,就會在這里出現問題。特別對初學者來講,我們有必要來好好研究下這個概念。我會以實際代碼來演示,相干示例代碼上傳至 這里 。

      首先通過1句話來解釋:深拷貝就是內容拷貝,淺拷貝就是指針拷貝。

       深拷貝就是拷貝出和原來僅僅是值1樣,但是內存地址完全不1樣的新的對象,創建后和原對象沒有任何關系。淺拷貝就是拷貝指向原來對象的指針,使原對象的援用計數+1,可以理解為創建了1個指向原對象的新指針而已,并沒有創建1個全新的對象。

(1)非容器類對象的深拷貝、淺拷貝

// 字符串是直接賦值的,右邊如果是copy,那末就是淺拷貝;右邊如果是mutableCopy,那末就是深拷貝。 NSString *string1 = @"helloworld"; NSString *string2 = [string1 copy]; // 淺拷貝 NSString *string3 = [string1 mutableCopy]; // 深拷貝 NSMutableString *string4 = [string1 copy]; // 淺拷貝 NSMutableString *string5 = [string1 mutableCopy]; // 深拷貝 NSLog(@"string1 = %d;string2 = %d",string1,string2); NSLog(@"string1 = %d;string3 = %d",string1,string3); NSLog(@"string1 = %d;string4 = %d",string1,string4); NSLog(@"string1 = %d;string5 = %d",string1,string5);

打印結果以下:



      我這里用%d格式化打印出字符串對象的內存地址。我這里主要通過內存地址來判斷是深拷貝還是淺拷貝,在該案例中,不管是深拷貝還是淺拷貝,字符串對象的值都是1樣的,所以暫且就不打印值了,而只打印地址。這里的原字符串是直接賦值的,可以發現,右邊如果使用copy,那末打印出的內存地址是1樣的,表示是淺拷貝,只拷貝出了指向原對象的指針,沒有創建出新的對象。如果右邊使用mutableCopy,那末打印出的不1樣的內存地址,表示創建了1個新的對象,是深拷貝。

     簡單說明1下甚么是非容器類對象,像NSString,NSNumber這些不能包括其他對象的叫做非容器類。如NSArray和NSDictionary可以容納其他對象的叫做容器類對象。

做1個小小的總結:

-- 淺拷貝類似retain,援用計數對象+1.創建1個指針;

-- 深拷貝是真正意義上的拷貝,是創建1個新對象。copy屬性表示兩個對象內容相同,新的對象retain為1,與原對象的援用計數無關,原對象沒有改變。copy減少對象對上下文的依賴。

-- retain屬性表示兩個對象地址相同(建立1個指針,指針拷貝),內容固然相同,這個對象的retain值+1.也就是說,retain是指針拷貝,copy是內容拷貝。


(2)改變字符串的創建方式,使用stringWithFormat創建字符串,而不是直接賦值

// 結果同上。右邊如果是copy,那末就是淺拷貝;右邊如果是mutableCopy,那末就是深拷貝。 NSString *string1 = [NSString stringWithFormat:@"helloworld"]; NSString *string2 = [string1 copy]; // 淺拷貝 NSString *string3 = [string1 mutableCopy]; // 深拷貝 NSMutableString *string4 = [string1 copy]; // 淺拷貝 NSMutableString *string5 = [string1 mutableCopy]; // 深拷貝 NSLog(@"string1 = %d;string2 = %d",string1,string2); NSLog(@"string1 = %d;string3 = %d",string1,string3); NSLog(@"string1 = %d;string4 = %d",string1,string4); NSLog(@"string1 = %d;string5 = %d",string1,string5);

打印結果以下:



結果同(1)。由于都是不可變字符串,創建方式其實不影響拷貝方式。所以可以得出結論,對字符串這類非容器類對象,copy是淺拷貝,mutable是深拷貝。



(3)以上測試的都是不可變字符串,這里來嘗試下可變字符串

// 如果是1個MutableString,那末不管是copy,mutableCopy,都會創建1個新對象。 NSMutableString *string1 = [NSMutableString stringWithString:@"helloworld"]; NSString *string2 = [string1 copy]; // 深拷貝 NSString *string3 = [string1 mutableCopy]; // 深拷貝 NSMutableString *string4 = [string1 copy]; // 深拷貝 NSMutableString *string5 = [string1 mutableCopy]; // 深拷貝 NSLog(@"string1 = %d;string2 = %d",string1,string2); NSLog(@"string1 = %d;string3 = %d",string1,string3); NSLog(@"string1 = %d;string4 = %d",string1,string4); NSLog(@"string1 = %d;string5 = %d",string1,string5);


打印結果以下:


   可以看到,對MutableString,右邊不管是copy還是mutableCopy,都會創建1個新對象,都是屬于深拷貝。

現在我們對以上代碼做1點修改:

// 如果是1個MutableString,那末不管是copy,mutableCopy,都會創建1個新對象。 NSMutableString *string1 = [NSMutableString stringWithString:@"helloworld"]; NSString *string2 = [string1 copy]; // 深拷貝 NSString *string3 = [string1 mutableCopy]; // 深拷貝 NSMutableString *string4 = [string1 copy]; // 深拷貝 NSMutableString *string5 = [string1 mutableCopy]; // 深拷貝 NSLog(@"string1 = %d;string2 = %d",string1,string2); NSLog(@"string1 = %d;string3 = %d",string1,string3); NSLog(@"string1 = %d;string4 = %d",string1,string4); NSLog(@"string1 = %d;string5 = %d",string1,string5); // 增加以下代碼 [string4 appendString:@"MMMMMM"]; [string5 appendString:@"11111"]; NSLog(@"string4 = %@",string4); NSLog(@"string5 = %@",string5);

我增加了4行代碼,我想要檢驗1下對1個可變字符串履行copy和mutableCopy后,返回的字符串是不是可變。同時為了檢驗在哪1行出現crash,我提早打1個異常斷點。對NSMutableString有appendString方法,而NSString沒有appendString方法,所以這類檢驗應當是沒有問題的。運行代碼后,會在[string4 apendString:@“MMMMM”];這1行出現崩潰。經過實際測試,可得出以下結論:

-- 對可變對象的復制,都是深拷貝;

-- 可變對象copy后返回的對象是不可變的,mutableCopy后返回的對象是可變的。


(4)我們上面提到的都是系統類,如果是我們自定義的類,復制結果又是怎樣呢?我下面定義1個Person類,實現以下:

Person.h

#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @end


Person.m

#import "Person.h" @interface Person()<NSCopying, NSMutableCopying> @end @implementation Person // 對應copy方法 - (id)copyWithZone:(NSZone *)zone { Person *person = [[Person allocWithZone:zone] init]; person.name = self.name; // 這里的self就是被copy的對象 person.age = self.age; return person; } - (id)mutableCopyWithZone:(NSZone *)zone { Person *person = [[Person allocWithZone:zone] init]; person.name = self.name; person.age = self.age; return person; } @end

       首先聲明1下為何要實現上述的copyWithZone和mutableCopyWithZone方法?其實在iOS中其實不是所有的對象都支持copy、mutableCopy方法,只有遵照NSCopying協議的類可以發送copy消息,遵照NSMutableCopying協議的類才可以發送mutableCopy消息,否則就會崩潰。我們可以非常方便的使用系統類中的copy,mutableCopy方法,是由于這些系統類本身就實現了NSCopying,NSMutableCopy協議,大家可以進入接口文檔進行查看。

然后編寫測試代碼以下:

// Person類必須實現copyWithZone和mutableCopyWithZone方法。 Person *person = [[Person alloc] init]; person.name = @"Jack"; person.age = 23; Person *copyPerson = [person copy]; // 深拷貝 Person *mutableCopyPerson = [person mutableCopy]; // 深拷貝 NSLog(@"person = %d;copyPerson = %d",person,copyPerson); NSLog(@"person = %d;mutableCopyPerson = %d",person,mutableCopyPerson);

打印結果以下:


可以看到不管是用copy還是mutableCopy,復制后都創建了1個新的對象。為何呢?由于我們本來就在copyWithZone: ,mutableCopyWithZone方法中創建了1個新對象啊,所以1點都不奇怪。


(5)從上述(4)中可以看到我的Person自定義對象在copy后是創建了1個全新的對象,那末這個對象中的屬性呢?這些屬性是深拷貝還是淺拷貝呢?

NSMutableString *otherName = [[NSMutableString alloc] initWithString:@"Jack"]; Person *person = [[Person alloc] init]; person.name = otherName; person.age = 23; [otherName appendString:@" and Mary"]; NSLog(@"person.name = %@",person.name);

打印結果以下:


打印的結果是"Jack",而不是”Jack and Mary“. 說明在履行person.name = otherName;的時候是重新創建了1個字符串。但是請大家注意,這里我name的屬性修飾符是copy,如果把copy改成strong會變成怎樣樣呢?

      對,沒錯,name改成strong后答案就是”Jack and Mary“。所以在這里我們可以得出以下小小的結論:

-- 由于這里的otherName是可變的,person.name的屬性是copy,所以創建了新的字符串,屬于深拷貝;

-- 如果person.name設置為strong,那末就是淺拷貝。由于strong會持有原來的對象,使原來的對象的援用計數+1,其實就是指針拷貝。

-- 固然,這里用strong還是copy,取決于實際需求。


(6)與上面(5)類似,我現在修改代碼以下:

NSString *otherName = @"jack"; Person *person = [[Person alloc] init]; person.name = otherName; person.age = 23; NSLog(@"othername = %d;person.name = %d",otherName,person.name);

其實這里很好理解,不管person.name是strong還是copy,都是指針拷貝。指向的都是otherName的內存地址。

現修改代碼以下:

NSString *otherName = @"jack"; Person *person = [[Person alloc] init]; person.name = [otherName copy]; person.age = 23; NSLog(@"othername = %d;person.name = %d",otherName,person.name);

一樣的,不管person.name是strong還是copy,都是指針拷貝。指向的都是otherName的內存地址。由于對不可變對象履行copy1般都是淺拷貝,這沒問題。


再次修改代碼以下:

NSString *otherName = @"jack"; Person *person = [[Person alloc] init]; person.name = [otherName mutableCopy]; person.age = 23; NSLog(@"othername = %d;person.name = %d",otherName,person.name);
不管person.name是strong還是copy,都是內容拷貝。創建1個全新的對象。由于對不可變對象履行mutableCopy1般都是深拷貝,也沒問題。


(7)講了這么多非容器對象,最后我們來說講容器對象Array。先講不可變的容器對象

NSArray *array01 = [NSArray arrayWithObjects:@"a",@"b",@"c", nil]; NSArray *copyArray01 = [array01 copy]; NSMutableArray *mutableCopyArray01 = [array01 mutableCopy]; NSLog(@"array01 = %d,copyArray01 = %d",array01,copyArray01); NSLog(@"array01 = %d,mutableCopyArray01 = %d",array01,mutableCopyArray01); NSLog(@"array01[0] = %d,array01[1] = %d,array01[2] = %d",array01[0],array01[1],array01[2]); NSLog(@"copyArray01[0] = %d,copyArray01[1] = %d,copyArray01[2] = %d",copyArray01[0],copyArray01[1],copyArray01[2]); NSLog(@"mutableCopyArray01[0] = %d,mutableCopyArray01[1] = %d,mutableCopyArray01[2] = %d",mutableCopyArray01[0],mutableCopyArray01[1],mutableCopyArray01[2]);

打印結果以下:



我們可以得出以下結論:

-- copyArray01和array01指向的是同1個對象,包括里面的元素也是指向相同的指針。

-- mutableCopyArray01和array01指向的是不同的對象,但是里面的元素指向相同的對象,mutableCopyArray01可以修改自己的對象。

-- copyArray01是對array01的指針復制(淺復制),而mutableCopyArray01是內容復制。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------打個分割線

上面的是不可變容器NSArray,這里測試下可變容器NSMutableArray:

NSMutableArray *array01 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil]; NSArray *copyArray01 = [array01 copy]; NSMutableArray *mutableCopyArray01 = [array01 mutableCopy]; NSLog(@"array01 = %d,copyArray01 = %d",array01,copyArray01); NSLog(@"array01 = %d,mutableCopyArray01 = %d",array01,mutableCopyArray01); NSLog(@"array01[0] = %d,array01[1] = %d,array01[2] = %d",array01[0],array01[1],array01[2]); NSLog(@"copyArray01[0] = %d,copyArray01[1] = %d,copyArray01[2] = %d",copyArray01[0],copyArray01[1],copyArray01[2]); NSLog(@"mutableCopyArray01[0] = %d,mutableCopyArray01[1] = %d,mutableCopyArray01[2] = %d",mutableCopyArray01[0],mutableCopyArray01[1],mutableCopyArray01[2]);

打印的結果以下:


可得結論以下:

-- 容器對象和非容器對象類似,可變對象復制(copy,mutableCopy)的都是1個新對象;不可變對象copy是淺復制,mutableCopy是深復制。

-- 對容器而言,元素對象始終是指針復制。


      以上觸及的也只是1部份,想要對深拷貝、淺拷貝有更加深入的了解,必須首先要對內存管理較為熟習,然后在實際開發中不斷去實踐,才會為所欲為。


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日本免费一区二区三区最新vr | 日本一区二区三区在线观看视频 | 亚洲国产成人在线观看 | 三级全黄在线观看www桃花 | 中文字幕视频一区 | 亚洲精品人成无码中文毛片 | 亚州精品一区二区三区 | 一区在线看 | 99r8这里精品热视频免费看 | 日韩精品一区二区三区在线观看l | 亚洲国产欧美日韩精品小说 | 日本特黄一级 | 欧美啊啊 | 春色视频免费版高清在线观看 | 国产综合影院 | 波多野结衣 一区二区 | 中文字幕无线码欧美成人 | 国产在线精品福利一区二区三区 | 免费大片在线观看www | 欧美色图偷窥自拍 | 久久久久一区二区三区 | 啪啪国产视频 | 国产日产欧美精品一区二区三区 | 福利一区三区 | 日本高清精品动漫 | 国产最新一区二区三区天堂 | 国产一区曰韩二区欧美三区 | 亚洲精品高清在线 | 日本在线www | 亚洲日本在线免费观看 | 最新中文字幕av专区 | 国产精品自拍一区 | 亚洲精品欧美精品 | 国产国产人在线成免费视频69 | 亚洲精品一区二区三区婷婷月 | 亚洲三级精品 | 亚洲一级在线 | 欧美日韩一品道 | 亚洲综合精品一区二区三区中文 | 精品欧美一区二区三区在线观看 | 久久a级片 |