值類型
在 Swift 中,所有的基本類型:整數(shù)(Integer)址儒、浮 點(diǎn)數(shù)(floating-point)演训、布爾值(Boolean)、字符串(string)汁咏、數(shù)組(array)和字典(dictionary)亚斋,都是 值類型,并且在底層都是以結(jié)構(gòu)體的形式所實(shí)現(xiàn)攘滩。
在 Swift 中帅刊,所有的結(jié)構(gòu)體和枚舉類型都是值類型。這意味著它們的實(shí)例漂问,以及實(shí)例中所包含的任何值類型屬 性赖瞒,在代碼中傳遞的時(shí)候都會被復(fù)制。
引用類型
除了值類型蚤假,都是引用類型栏饮,在Swift中類就是引用類型,和Java類似磷仰,在OC中擁不擁有isa指針的區(qū)別袍嬉。
與值類型不同,引用類型在被賦予到一個(gè)變量灶平、常量或者被傳遞到一個(gè)函數(shù)時(shí)伺通,其值不會被拷貝。因此民逼,引用的
是已存在的實(shí)例本身而不是其拷貝
1. 值類型 let var
值類型和OC中的基本數(shù)據(jù)類型一致泵殴,其內(nèi)存在棧空間里拼苍,當(dāng)作用域結(jié)束系統(tǒng)自動回收笑诅。
- 用let去申明一個(gè)值類型调缨,對該變量進(jìn)行拷貝,保證這個(gè)變量的值不被修改吆你;
- 用var去申明一個(gè)值類型弦叶,對該變量進(jìn)行拷貝,新變量可進(jìn)行修改值妇多,不影響原來的變量伤哺;
Value Type
2. 引用類型 let var
除了值類型,其他都是引用類型者祖,引用類型的實(shí)例被稱之為對象立莉,值類型的實(shí)例只能被稱之為實(shí)例,申明的變量在椘呶剩空間里是一個(gè)引用蜓耻,創(chuàng)建的對象放在堆空間里,引用指向堆空間創(chuàng)建的對象械巡。
- 用let申明一個(gè)引用類型刹淌,只能保證該實(shí)例不被指向其他實(shí)例;
- 用var申明一個(gè)引用類型讥耗,這個(gè)實(shí)例可以被其他實(shí)例賦值有勾,就是該實(shí)例的引用會指向新值;
創(chuàng)建3個(gè)變量
let origin = ViewMode()
let passLetOrigin = origin
var passVarOrigin = origin
其內(nèi)存情況古程,如圖所示蔼卡,3個(gè)變量的內(nèi)存地址一致,引用都指向同一個(gè)堆空間里的創(chuàng)建對象
我們再創(chuàng)建一個(gè)對象otherObject
let otherObject = ViewMode()
這時(shí)候內(nèi)存里應(yīng)該是這樣的
otherObject指向自己新創(chuàng)建的對象
如果將passVarOrigin = otherObject內(nèi)存會怎樣呢籍琳?
如圖菲宴,passVarOrigin的指針地址變成了0x456,而引用也指向了otherObject的對象趋急。
實(shí)際上PassvarOrigin進(jìn)行了一次析構(gòu) 將就對象銷毀了 再進(jìn)行賦值
這時(shí)候修改實(shí)例變量
origin.name = "1.0"
passLetOrigin.name = "2.0"
passVarOrigin.name = "3.0"
print("origin.name: \(origin.name)")
print("passLetOrigin.name: \(passLetOrigin.name)")
print("passVarOrigin.name: \(passVarOrigin.name)")
print("-----------------------")
print("origin.name: \(origin.name)")
print("passLetOrigin.name: \(passLetOrigin.name)")
打印結(jié)果:
origin.name: Optional("2.0")//因?yàn)閛rigin與passLetOrigin指向同一個(gè)實(shí)例,passLetOrigin.name后被修改為2.0势誊,所以沒有打印1.0
passLetOrigin.name: Optional("2.0")
passVarOrigin.name: Optional("3.0")
-----------賦值后------------
origin.name: Optional("2.0")//
passLetOrigin.name: Optional("2.0")
賦值后呜达,origin.name和passLetOrigin.name的值并沒有受到passVarOrigin.name的更改而改變。
值類型和引用類型的作用
選擇值類型而不是引用類型的一個(gè)主要原因是能讓你的代碼變得更加簡單粟耻。你在任何情況下用一個(gè)值類型查近,都能保證值不會在其他代碼里被改變,這在多線程很有用挤忙,保證其線程安全霜威。
在值不被修改的情況下,值類型和引用類型看起來是完全一樣的册烈。
你也許會想戈泼,寫一個(gè)完全不可變的類,這或許是有價(jià)值的,使用Cocoa的NSObject能簡化這個(gè)過程大猛,并且能很好地保持原有的語義扭倾。
現(xiàn)在,你能通過使用不可變的存儲屬性挽绩,以及避免暴露修改數(shù)據(jù)的接口膛壹,從而在Swift里實(shí)現(xiàn)一個(gè)不可變的類。事實(shí)上唉堪,大多數(shù)的Cocoa類模聋,比如NSURL等,都被設(shè)計(jì)為不可變的類唠亚,然而撬槽,Swift當(dāng)前并沒有提供任何語言機(jī)制去強(qiáng)制申明一個(gè)類不可改變(比如子類化就能修改一個(gè)類的實(shí)現(xiàn)),只有結(jié)構(gòu)體和枚舉才是強(qiáng)制不可變的趾撵。
如何選擇
所以如果你想要創(chuàng)建一個(gè)新的類型侄柔,你怎么選擇?當(dāng)你寫Cocoa程序的時(shí)候占调,大多數(shù)APIs都需要從NSObject繼承暂题,你就已經(jīng)是一個(gè)類了(引用類型),針對其他情況究珊,這里有些指導(dǎo)規(guī)則:
使用值類型薪者,當(dāng):
通過使用==去比較實(shí)例的數(shù)據(jù)
你想得到一個(gè)實(shí)例的獨(dú)立副本
數(shù)據(jù)在多線程環(huán)境下被修改
使用引用類型(比如使用一個(gè)類),當(dāng):
通過使用===去判斷兩個(gè)實(shí)例是否恒等
你想要創(chuàng)建一個(gè)共享的剿涮,可變的對象
在Swift里言津,Array、String和Dictionary都是值類型取试,他們的行為和C語言中的int類似悬槽,每個(gè)實(shí)例都有自己的數(shù)據(jù),你不需要額外做任何事情瞬浓,比如做一個(gè)顯式的copy初婆,防止其他代碼在你不知情的情況下修改等,更重要的是猿棉,你能安全地在線程間傳遞它磅叛,而不需要使用同步技術(shù)。在提高安全性的精神下萨赁,這個(gè)模型將幫助你在Swift中寫出更多可預(yù)知的代碼弊琴。
自己的思考就是結(jié)構(gòu)體和類的選擇,而他們最大的區(qū)別在于是否需要繼承杖爽,官方指出敲董,數(shù)據(jù)結(jié)構(gòu)簡單紫皇,數(shù)據(jù)較小使用結(jié)構(gòu)體;