亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

通過源碼分析iOS中的深拷貝與淺拷貝

2019-10-21 18:39:51
字體:
來源:轉載
供稿:網友

前言

關于iOS中對象的深拷貝淺拷貝的文章有很多,但是大部分都是基于打印內存地址來推導結果,這篇文章是從源碼的角度來分析深拷貝和淺拷貝。

深拷貝和淺拷貝的概念

拷貝的方式有兩種:深拷貝和淺拷貝。

  • 淺拷貝又叫指針拷貝,比如說有一個指針,這個指針指向一個字符串,也就是說這個指針變量的值是這個字符串的地址,那么此時對這個字符串進行指針拷貝的意思就是又創建了一個指針變量,這個指針變量的值是這個字符串的地址,也就是這個字符串的引用計數+1。
  • 深拷貝又叫內容拷貝,比如有一個指針,這個指針指向一個字符串,也就是說這個指針變量的值是這個字符串的地址值,那么此時對這個字符串進行內容拷貝,就會創建一個新的指針,在一個新的地址區域創建一個字符串,這個字符串的值和原字符串的值相同,新的指針指向這個新創建的字符串。這時原字符串的引用計數沒有+1。

淺拷貝就是拷貝后,并沒有進行真正的復制,而是復制的對象和原對象都指向同一個地址

深拷貝是真正的復制了一份,復制的對象指向了新的地址

源碼,iOS,深拷貝,淺拷貝

從上圖可以看出,淺拷貝A指針改變了所指向的內容B指針也指向被修改后的內容。如果有些地方用到B指針,不希望在A指向的內容發生變化時也跟著變化,則需要用到深拷貝。

通俗理解為:淺拷貝好比你的影子,你死了,影子也沒了;深拷貝好比克隆人,你死了,它還在。

對象的copy和mutableCopy方法

不管是集合對象還是非集合對象,接收到copy和mutableCopy消息時,都遵循以下準則:

  • copy返回immutable對象
  • mutableCopy返回mutable對象

下面對非集合對象和集合對象的copy和mutableCopy方法進行具體的闡述。

1.非集合類對象的copy和mutableCopy方法

非集合類對象指的是NSString,NSNumber...這些類。下面的例子以NSString類為例。

首先來看immutable對象拷貝的例子:

 NSString *string = @"test"; NSString *copyString = [string copy]; NSMutableString *mutableCopyString = [string mutableCopy];  NSLog(@"%p /n %p /n %p /n", string, copyString, mutableCopyString);

打印結果:

0x101545068 
0x101545068 
0x60000024e940

通過打印結果我們可以看出來,copyString和string的地址值一樣,而mutableCopyString和string的地址值不一樣,這就說明imutable對象的copy方法進行了淺拷貝,mutableCopy方法進行了深拷貝。

再來看看mutable對象拷貝的例子:

 NSMutableString *string = [[NSMutableString alloc] initWithString:@"test"]; NSString *copyString = [string copy]; NSMutableString *mutableCopyString = [string mutableCopy];  NSLog(@"%p /n%p /n%p /n", string, copyString, mutableCopyString);

打印結果:

0x600000240e40 
0xa000000747365744 
0x6000002411a0

通過打印結果可以看出來,copyString和string的內存地址不同,mutableCopyString和string的內存地址也不同。這說明mutable對象的copy方法和mutableCopy方法都進行了深拷貝。

總結起來就是:

immutable對象的copy方法進行了淺拷貝
immutable對象的mutableCopy方法進行了深拷貝
mutable對象的copy方法進行了深拷貝
mutable對象的mutableCopy方法進行了深拷貝。

用代碼表示就是:

 [immutableObject copy];//淺拷貝 [immutableObject mutableCopy];//深拷貝 [mutableObject copy];//深拷貝 [mutableObject mutableCopy];//深拷貝

以上是通過打印內存地址得出的結論,下面我們通過查看源碼來證實一下我們的結論。

在opensource.apple.com的git倉庫中的runtime源碼中有NSObject.mm這個文件,在這個文件中有copy和mutableCopy方法的實現:

- (id)copy { return [(id)self copyWithZone:nil];}- (id)mutableCopy { return [(id)self mutableCopyWithZone:nil];}

我們發現copy和mutableCopy方法只是簡單的調用了copyWithZone:和mutableCopyWithZone:兩個方法。然后我在searchcode.com中找到了NSString和NSMutableString的Source Code。

NSString.m中,找到了關于copy的方法:

- (id)copyWithZone:(NSZone *)zone { if (NSStringClass == Nil) NSStringClass = [NSString class]; return RETAIN(self);}- (id)mutableCopyWithZone:(NSZone*)zone { return [[NSMutableString allocWithZone:zone] initWithString:self];}

通過這個源碼我們知道了,對于NSString對象,調用copy方法就是調用了copyWithZone:方法。而copyWithZone:方法并沒有創建新的對象,而是使指針持有了原來的NSString對象,所以NSString的copy方法是淺拷貝。

而調用mutableCopy方法就是調用了mutableCopyWithZone:方法。從mutableCopyWithZone:的實現我們可以看到,這個方法是創建了一個新的可變的字符串對象。因此NSString的mutableCopy方法是深拷貝。

NSMutableString.m中,只找到了copy和copyWithZone:方法,并沒有找到mutableCopyWithZone:方法:

-(id)copy { return [[NSString alloc] initWithString:self];}-(id)copyWithZone:(NSZone*)zone { return [[NSString allocWithZone:zone] initWithString:self];}

對NSMutableString對象調用copy方法會調用這里的copyWithZone:方法的實現,我們可以看到這里創建了一個新的不可變的字符串。所以對NSMutableString對象執行copy方法是深拷貝。

由于在NSMutableString中沒有實現mutableCopyWithZone:方法,所以會調用父類的mutableCopyWithZone:方法,也就是NSString類的mutableCopyWithZone:方法,而我們知道,NSString類的mutableCopyWithZone:方法會創建一個新的可變字符串。所以對NSMutableString對象執行mutableCopy方法是深拷貝。

2.集合對象的copy和mutableCopy

集合對象指的是NSArray,NSDictionary,NSSet等之類的對象。下面以NSArray為例看看immutable對象使用copy和mutableCopy的例子:

 NSArray *array = @[@"1", @"2", @"3"]; NSArray *copyArray = [array copy]; NSMutableArray *mutableCopyArray = [array mutableCopy];  NSLog(@"%p/n%p/n%p", array, copyArray, mutableCopyArray);

打印結果:

0x60400025bed0
0x60400025bed0
0x60400025c2f0

通過打印結果可以看出來,copyArray的地址和array的地址是一樣的,說明對array進行copy是進行淺拷貝。而

mutableCopyArray的地址和array的地址是不一樣的,說明對array進行mutableCopy是進行了深拷貝。

再來看mutable對象執行copy和mutableCopy的例子:

 NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[@"1", @"2", @"3"]]; NSArray *copyArray = [array copy]; NSMutableArray *mutableCopyArray = [array mutableCopy];  NSLog(@"%p/n%p/n%p", array, copyArray, mutableCopyArray);

打印結果:

0x604000447440
0x604000447050
0x604000447080

通過打印結果可以看出,copyArray和mutableCopyArray的地址都和array的地址不同,這說明對可變數組進行copy和mutableCopy操作都進行了深拷貝。

因此得出結論:

在集合類對象中,對immutable對象進行copy操作是淺拷貝,進行mutableCopy操作是深拷貝。對mutable對象進行copy操作是深拷貝,進行mutableCopy操作是深拷貝。

用代碼表示就是:

 [immutableObject copy];//淺拷貝 [immutableObject mutableCopy];//深拷貝 [mutableObject copy];//深拷貝 [mutableObject mutableCopy];//深拷貝

以上是通過打印內存地址得到的結論,下面我們通過源碼來驗證一下我們的結論。

NSArray.m中,我找到了copyWithZone:和mutableCopyWithZone:方法。

- (id)copyWithZone:(NSZone *)zone{ return RETAIN(self);}- (id)mutableCopyWithZone:(NSZone*)zone{ if (NSMutableArrayClass == Nil) NSMutableArrayClass = [NSMutableArray class]; return [[NSMutableArrayClass alloc] initWithArray:self];}

當調用copy方法時,實際上是執行了這里的copyWithZone:方法,在這個方法里面并沒有創建新的對象,而只是持有了舊的對象,因此,對于不可變的數組對象,執行copy操作是淺拷貝。

當調用mutableCopy方法時,實際上是執行了這里的mutableCopyWithZone:方法,在這個方法里面,利用原來的數組對象,創建了一個新的可變數組對象,因此對于不可變的數組對象,執行mutableCopy操作是深拷貝。

NSArray.m這個文件的第825行是NSMutableArray的實現。在第875行找到了copyWithZone:的實現,沒有找到mutableCopyWithZone:的實現:

- (id)copyWithZone:(NSZone*)zone{ if (NSArrayClass == Nil) NSArrayClass = [NSArray class]; return [[NSArrayClass alloc] initWithArray:self copyItems:YES];}

當調用copy方法時,實際是調用了這里的copyWithZone:方法,在這個方法的實現里,是利用原來的可變數組創建了一個新的不可變數組,因此對可變數組執行copy操作是深拷貝。

當調用mutableCopy時,由于NSMutableArray本身沒有實現mutableCopyWithZone:方法,所以會調用父類也就是NSArray類的實現,而通過上面我們也能看到NSArray的實現:利用原數組創建了一個新的可變數組,因此,對可變數組進行mutableCopy操作是深拷貝。

回答經典面試題

面試題:為什么NSString類型的成員變量的修飾屬性用copy而不是strong呢?

首先要搞清楚的就是對NSString類型的成員變量用copy修飾和用strong修飾的區別。如果使用了copy修飾符,那么在給成員變量賦值的時候就會對被賦值的對象進行copy操作,然后再賦值給成員變量。如果使用的是strong修飾符,則不會執行copy操作,直接將被賦值的變量賦值給成員變量。

假設有一個NSString類型的成員變量string,對其進行賦值:

 NSString *testString = @"test"; self.string = testString;

如果該成員變量是用copy修飾的,則等價于:

self.string = [testString copy];

如果是用strong修飾的,則沒有copy操作:

self.string = testString;

知道了使用copy和strong的區別后,我們再來分析為什么要使用copy修飾符。先看一段代碼:

 NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@"test"]; self.string = mutableString; NSLog(@"%@", self.string); [mutableString appendString:@"addstring"]; NSLog(@"%@", self.string);

如果這里成員變量string是用strong修飾的話,打印結果就是:

2018-09-04 10:50:16.909998+0800 copytest[2856:78171] test
2018-09-04 10:50:16.910128+0800 copytest[2856:78171] testaddstring

很顯然,當mutableString的值發生了改變后,string的值也隨之發生改變,因為self.string = mutableString;這行代碼實際上是執行了一次指針拷貝。string的值隨mutableString的值的發生改變這顯然不是我們想要的結果。

如果成員變量string是用copy修飾,打印結果就是:

2018-09-04 10:58:07.705373+0800 copytest[3024:84066] test
2018-09-04 10:58:07.705496+0800 copytest[3024:84066] test

這是因為使用copy修飾符后,self.string = mutableString;就等價于self.string = [mutableString copy];,也就是進行了一次深拷貝,所以mutableString的值再發生變化就不會影響到string的值。

回答面試題:

NSString類型的成員變量使用copy修飾而不是strong修飾是因為有時候賦給該成員變量的值是NSMutableString類型的,這時候如果修飾符是strong,那成員變量的值就會隨著被賦值對象的值的變化而變化。若是用copy修飾,則對NSMutableString類型的值進行了一次深拷貝,成員變量的值就不會隨著被賦值對象的值的改變而改變。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到IOS開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美特黄级在线| 成人乱人伦精品视频在线观看| 午夜精品久久久久久久久久久久| 国产亚洲欧美另类中文| 性欧美办公室18xxxxhd| 最近更新的2019中文字幕| 欧美怡春院一区二区三区| 97超碰蝌蚪网人人做人人爽| 欧美另类老女人| 欧美风情在线观看| 亚洲娇小xxxx欧美娇小| 欧美日韩一区二区在线播放| 久久国产精品首页| 久久视频在线看| 午夜精品免费视频| 在线亚洲男人天堂| 欧美另类高清videos| 久久av在线播放| 国产精品www网站| 国产极品jizzhd欧美| 日韩精品中文字幕在线播放| 国产精品免费一区二区三区都可以| 久久99久久99精品中文字幕| 国产精品久久9| 亚洲欧洲第一视频| 亚洲福利影片在线| 免费97视频在线精品国自产拍| 亚洲国产97在线精品一区| 成人国产在线视频| 国产精品美女999| 亚洲福利在线观看| 久久久久久久电影一区| 色系列之999| 欧美极品少妇全裸体| 国产z一区二区三区| 国产成人精品网站| 欧美大片在线看免费观看| 97视频在线看| 免费91在线视频| 久久精品亚洲热| 26uuu亚洲国产精品| 91产国在线观看动作片喷水| 琪琪亚洲精品午夜在线| 欧美有码在线视频| 精品一区精品二区| 久久亚洲一区二区三区四区五区高| 日韩经典中文字幕在线观看| 国产精品久久久久久久久久久新郎| 欧美多人爱爱视频网站| 亚洲美女性生活视频| 亚洲第一黄色网| 欧美肥婆姓交大片| 国产一区视频在线播放| 一本大道香蕉久在线播放29| 亚洲福利视频网| 日本久久精品视频| 亚洲qvod图片区电影| 日韩电影大全免费观看2023年上| 亚洲成人久久一区| 亚洲欧洲免费视频| 97精品伊人久久久大香线蕉| 欧美激情日韩图片| 精品久久久久久中文字幕大豆网| 国内精品美女av在线播放| 日韩黄色av网站| 欧美理论片在线观看| 成人午夜黄色影院| 中文字幕在线看视频国产欧美在线看完整| 日韩影视在线观看| 欧美日韩中文在线观看| 国产91热爆ts人妖在线| 中文字幕亚洲一区二区三区五十路| 国产成人午夜视频网址| 亚洲福利视频在线| 欧美一级淫片播放口| 国产欧美在线视频| 精品久久久久久久久久久久久久| 夜夜嗨av色综合久久久综合网| 亚洲一区二区三区在线视频| 国模gogo一区二区大胆私拍| 欧美视频国产精品| 久久频这里精品99香蕉| 日韩在线观看你懂的| 久久伊人免费视频| 国产精品成av人在线视午夜片| 亚洲国产高清自拍| 欧美综合第一页| 久久精品成人动漫| 国产一区二区三区在线免费观看| 日韩av电影手机在线| 久久久久久久国产精品| 国产精品精品视频| 欧美专区中文字幕| 国产欧美在线播放| 欧美色道久久88综合亚洲精品| 国产精品久久久久久久久影视| 亚洲国产精品久久久久秋霞蜜臀| 久久中文精品视频| 欧美小视频在线观看| 欧美性猛交xxxx免费看| 久久久久久国产精品| 国内成人精品一区| 国产精品亚洲网站| 久久精品国产91精品亚洲| 亚洲网站在线观看| 中文字幕久久精品| 国产精品www色诱视频| 日本一区二区在线免费播放| 日韩专区在线播放| 欧美极品少妇xxxxⅹ裸体艺术| 亚洲精品永久免费精品| 国产日韩欧美一二三区| 国产精品久久久久7777婷婷| 亚洲欧美一区二区三区情侣bbw| 日韩欧美aⅴ综合网站发布| 国产成人精品免费视频| 亚洲午夜性刺激影院| 国产精品久久精品| 久久99热精品这里久久精品| 69视频在线播放| 欧美亚洲第一页| 精品国产乱码久久久久久虫虫漫画| 精品动漫一区二区三区| 日韩中文视频免费在线观看| 日韩中文字幕免费看| 久久久精品国产网站| 欧美黑人一区二区三区| 日韩久久午夜影院| 欧美激情视频给我| 在线观看日韩欧美| 影音先锋欧美在线资源| 日韩av在线天堂网| 亚洲www在线| 亚洲成人精品视频在线观看| 久久777国产线看观看精品| zzijzzij亚洲日本成熟少妇| 久久久av电影| 日韩欧美成人免费视频| 亚洲毛片在线观看.| 国产精品久久久久一区二区| 黑人极品videos精品欧美裸| 亚洲精品久久久一区二区三区| 亚洲mm色国产网站| 热久久免费国产视频| 揄拍成人国产精品视频| 国产激情综合五月久久| 亚洲国产第一页| 欧美性生交xxxxx久久久| 国产精品igao视频| 国产精品视频免费在线| 亚洲国产欧美精品| 九九热精品视频| 国产精品一区二区三区免费视频| 亚洲欧美制服第一页| 777午夜精品福利在线观看| 亚洲精品综合久久中文字幕| 久久成人精品一区二区三区| 亚洲亚裔videos黑人hd| 91网站免费看| 精品毛片三在线观看| 国产精品日韩久久久久| 日韩av第一页| 日韩暖暖在线视频| 欧美亚洲国产精品|