之前的編碼中,對于NSString的PRoperty修飾,習慣性使用copy,只是粗略的知道copy屬于深復制,retain/strong屬于淺復制,并沒有對其深究。最近需要詳細了解這一塊知識,在網上搜索相關內容,并且用代碼驗證,查看對比了內存地址,做一些總結。
一、之前對于copy和retain/strong的區別理解是這樣的:
copy是復制了源對象所在內存空間的數據,放入目的對象指針指向的內存空間,并且令目的對象引用計數為1,對于源對象的引用計數沒有影響;源對象內容的改變不會影響到目的對象。
retain/strong是目的對象指針指向源對象的內存空間,源對象的引用計數+1;源對象的改變會影響到目的對象。
mutablecopy返回的是可變的對象,copy返回的是不可變的對象。
二、代碼驗證探究
1、源對象為不可變 NSString
[objc] view plain copy
[html] view%20plain copy
retain的對象毫無懸念,還是源對象的內存地址;
copy的對象和我原來想的不一樣,竟然和retain一樣,也是源對象地址;這意味者并沒有對源對象內容進行復制,而只是復制了指針而已。如此看來copy方法并不一定會復制源對象的內容。之所以復制,肯定是因為兩個版本有所不同。而這里源對象是NSString不可變的,copy返回的也是不可變的,既然都不可變,那么這里的副本就沒有多大意義存在,就如同使用字符串常量,系統會為我們優化,聲明多個字符串,都是不可變且內容相同,那么系統就只申請一塊內存,這個道理是一樣的。指向一塊內存就可以了,所以這里的copy和retain的作用是一樣的。
mutablecopy的對象地址和源對象地址不同,說明重新開辟了內存,復制了一個副本。因為mutablecopy返回的對象是可變的,它的變動會影響到源對象,所以需要拷貝一份。
源對象為可變的NSMutableString
[html] view%20plain copy分析:
retain仍然和目的對象地址相同;
copy的地址和目的對象地址不相同,是因為源對象是可變的,目的對象不可變,當然需要兩個不同的版本;
mutablecopy形成了一個新的副本。因為兩個對象的改變會影響到對方,所以需要兩個版本。
得到的結論:
1、對于copy來說,如果源對象是不可變的,那么是淺拷貝,沒有必要深拷貝;如果源對象可變,為了安全性,深拷貝,生成副本。
2、對于mutablecopy來說,不管源對象是否可變,都是深拷貝。
因此我們在設置property的copy屬性時,如果希望對象跟著源對象的值變化,那么就是用retain;如果希望對象保持獨立的值,那就使用copy。當然這是在源對象為可變的情況下。
上面討論的是NSString相關的retain/copy/mutablecopy,在oc里面所有實現了NSCopying和NSMutableCopying協議的類,都具有copy和mutablecopy這兩個方法。這里引出了其他的oc對象的copy特性,它們是什么樣的,下一篇進行探究。
歡迎指正!
新聞熱點
疑難解答