1. 怎么用 copy 關(guān)鍵字醋安?
- 預(yù)備知識(shí) :
內(nèi)存的棧區(qū) : 由編譯器自動(dòng)分配釋放, 存放函數(shù)的參數(shù)值, 局部變量的值等. 其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧.
內(nèi)存的堆區(qū) : 一般由程序員分配釋放, 若程序員不釋放, 程序結(jié)束時(shí)可能由OS回收. 注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事, 分配方式倒是類似于鏈表.
copy方法和mutableCopy方法
如果你想要?jiǎng)?chuàng)建一個(gè)對(duì)象, 該對(duì)象與源對(duì)象的內(nèi)容一致, 那么你可以考慮用拷貝(copy或mutableCopy)
- 總結(jié):
1 copy拷貝出來的對(duì)象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
2.mutableCopy拷貝出來的對(duì)象類型總是可變類型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
深拷貝與淺拷貝
深拷貝 : 拷貝出來的對(duì)象與源對(duì)象地址不一致! 這意味著我修改拷貝對(duì)象的值對(duì)源對(duì)象的值沒有任何影響.
淺拷貝 : 拷貝出來的對(duì)象與源對(duì)象地址一致! 這意味著我修改拷貝對(duì)象的值會(huì)直接影響到源對(duì)象.
注意 ! 深拷貝與淺拷貝也有相對(duì)之分!!!看下面
對(duì)于NSString對(duì)象, 確實(shí)深拷貝就是深拷貝, 淺拷貝就是淺拷貝, 沒有任何異議.
但是對(duì)于NSArray, NSDictionary, NSSet這些容器類的對(duì)象呢? 當(dāng)然淺拷貝依然是指針拷貝, 那深拷貝意味著連同容器及其容器內(nèi)的對(duì)象一并拷貝嗎? 還是只拷貝容器對(duì)象, 對(duì)容器內(nèi)的對(duì)象則只是簡(jiǎn)單引用呢? 這里有兩種情況, 我姑且把它稱為不完全深拷貝與完全深拷貝
不完全深拷貝 - 就是只拷貝容器對(duì)象(拷貝一個(gè)殼), 而對(duì)于容器內(nèi)的對(duì)象則只保存一份引用.
完全深拷貝 - 就是連同容器內(nèi)的對(duì)象在內(nèi), 完完全全拷貝一份出來
ps : 默認(rèn)狀態(tài)下深拷貝指的是不完全深拷貝, 如要實(shí)現(xiàn)完全深拷貝, 則要重寫copyWithZone: 方法, 自行實(shí)現(xiàn)完全深拷貝的需求. 大體思路如下, 在copyWithZone: 里對(duì)象賦值上不直接賦值而是通過copy方法即可實(shí)現(xiàn)
-
總結(jié)
這里做出了一張圖, 幫助新手弄清楚copy與mutableCopy的區(qū)別, 大神請(qǐng)無視
2. block為什么要用copy?
首先, block是一個(gè)對(duì)象, 所以block理論上是可以retain/release的. 但是block在創(chuàng)建的時(shí)候它的內(nèi)存是默認(rèn)是分配在棧(stack)上, 而不是堆(heap)上的. 所以它的作用域僅限創(chuàng)建時(shí)候的當(dāng)前上下文(函數(shù), 方法...), 當(dāng)你在該作用域外調(diào)用該block時(shí), 程序就會(huì)崩潰.
意思就是 : 一般情況下你不需要自行調(diào)用copy或者retain一個(gè)block. 只有當(dāng)你需要在block定義域以外的地方使用時(shí)才需要copy. Copy將block從內(nèi)存棧區(qū)移到堆區(qū).
其實(shí)block使用copy是MRC留下來的也算是一個(gè)傳統(tǒng)吧, 在MRC下, 如上述, 在方法中的block創(chuàng)建在棧區(qū), 使用copy就能把他放到堆區(qū), 這樣在作用域外調(diào)用該block程序就不會(huì)崩潰. 但在ARC下, 使用copy與strong其實(shí)都一樣, 因?yàn)閎lock的retain就是用copy來實(shí)現(xiàn)的.