Swift結(jié)構(gòu)體內(nèi)存初探之寫時(shí)復(fù)制

? ? ? ? Swift賦予了結(jié)構(gòu)體很多余類相同的特性,以至于Swift推薦在程序中使用結(jié)構(gòu)體來存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)(關(guān)于類與結(jié)構(gòu)體的區(qū)別,以及在使用時(shí)的選擇不在本文討論范圍)。Swift標(biāo)準(zhǔn)庫中大部分都是通過結(jié)構(gòu)體實(shí)現(xiàn)的,典型的是Array,Dictionry,Set,String。

? ? ? ?結(jié)構(gòu)體是值類型,區(qū)別于類(引用類型,ARC內(nèi)存管理)。當(dāng)你將一個(gè)結(jié)構(gòu)體賦值給一個(gè)新的變量時(shí)或者作為參數(shù)傳遞給一個(gè)函數(shù)時(shí),Swift會(huì)對(duì)結(jié)構(gòu)體做一次復(fù)制,如果每次賦值或者傳參都要復(fù)制,似乎很昂貴。Swift沒那么傻,其實(shí)標(biāo)準(zhǔn)庫中有很多結(jié)構(gòu)體都使用了寫時(shí)復(fù)制的技術(shù)。圖-1以數(shù)組為例:

圖-1


? ? ?通過Playground的截圖看出:arrA賦值給arrB后,兩個(gè)數(shù)組的內(nèi)存地址是相同的,然后對(duì)arrA添加元素,arrA的指針起始地址發(fā)生了改變,arrB沒有變。說明,arrB確實(shí)是arrA的復(fù)制,但是只當(dāng)arrA發(fā)生改變時(shí)才會(huì)為arrA分配新的內(nèi)存空間。其實(shí)無論是否把a(bǔ)rrA賦值給arrB,只要arrA發(fā)生改變,就會(huì)重新為arrA分配內(nèi)存地址,這是因?yàn)橹嫡Z義的不變性,相當(dāng)于把新的值語義[1,2,3]賦值給值類型arrA,而不是改變?cè)瓉淼闹嫡Z義[1,2],arrA指針變化前后的起始地址是不同的可以看出。

? ? ? 編譯器對(duì)于值類型的復(fù)制優(yōu)化和值語義類型的寫時(shí)復(fù)制并不一樣。我們?cè)谧远x結(jié)構(gòu)體時(shí),如果結(jié)構(gòu)體包含引用類型的屬性,需要自己要實(shí)現(xiàn)寫時(shí)復(fù)制。

圖-2

? ? ? 如圖-2:Company結(jié)構(gòu)體中包含引用類型屬性employee,對(duì)comA的職員姓名修改其實(shí)只是修改引用指向的對(duì)象,引用本身不變,所以甚至可以用let來修飾。我們看到comB的職員姓名也相應(yīng)修改了,Company結(jié)構(gòu)體不具備我們想要的值語義。下面我們動(dòng)手實(shí)現(xiàn)Company的寫時(shí)復(fù)制,如圖-3:

圖-3

? ? ? 首先,我們需要Employee是可拷貝的,我們定義一個(gè)Copyable協(xié)議,然后讓Employee遵守這個(gè)協(xié)議。然后聲明一個(gè)employeeForWriting的計(jì)算屬性,changeEmployeeName方法每次執(zhí)行時(shí)就會(huì)返回一個(gè)employee的拷貝,對(duì)這個(gè)拷貝進(jìn)行修改。于是我們完成了自定義結(jié)構(gòu)體的寫時(shí)復(fù)制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容