事實上,結(jié)構(gòu)體 & 類 我們并不是很陌生,在我們各種熟悉語言中均是存在,比如,C、C++、OC等。
前面我們已經(jīng)知道 Swift 將 枚舉 著實豐富了很多,具體可以參見這篇文章。
而對于 結(jié)構(gòu)體 , Swift 也是對其寵愛有加。
有句話是這么說的來著:Swift 中,能用 結(jié)構(gòu)體 就不要用 類 ,除非需要 類 的那些特有的特性。
那么, Swift 中怎么定義 結(jié)構(gòu)體 跟 類 呢?
什么是 結(jié)構(gòu)體 & 類 ?
結(jié)構(gòu)體 & 類 是一種用于構(gòu)建程序代碼塊的靈活的穩(wěn)定的結(jié)構(gòu)??梢允褂门c定義常量,變量 和 函數(shù) 相同的語法來定義 屬性 和 方法 ,以向 結(jié)構(gòu)體 和 類 添加功能。(來自官網(wǎng)的翻譯)
誠如你所見,看似還是這么熟悉,卻又有一點不尋常,是的,我們可以向 結(jié)構(gòu)體 中添加 屬性&方法 ,就跟向 類 里面添加一樣一樣的!
所以,在 Swift 中 結(jié)構(gòu)體 已經(jīng)擴展到跟 類 灰常神似的地步。
那么問題來了,這兩者到底還有什么區(qū)別呢?
異同 In 結(jié)構(gòu)體 & 類 ?
Swift 中 類 和 結(jié)構(gòu)體 的共同處在于:
定義屬性用于存儲值
定義方法用于提供功能
定義下標(biāo)腳本用于訪問值
定義構(gòu)造器用于生成初始化值
通過擴展以增加默認(rèn)實現(xiàn)的功能
實現(xiàn)協(xié)議以提供某種標(biāo)準(zhǔn)功能
Swift 中 類 和 結(jié)構(gòu)體 的不同處在于:
結(jié)構(gòu)體不具有繼承性
結(jié)構(gòu)體不具備運行時強制類型轉(zhuǎn)換
結(jié)構(gòu)體不具備使用析構(gòu)器的能力
結(jié)構(gòu)體不具備使用引用計數(shù)的能力
綜上所述,如果我們需要構(gòu)建的代碼塊,只是需要 共同處 就能滿足,那么我們就選擇 結(jié)構(gòu)體 ;要是還需要 不同處 的特有功能,再選擇 類 。
語法
枚舉、結(jié)構(gòu)體、類 的語法非常類似,分別使用 enum、struct、class關(guān)鍵字來定義:
struct SomeStructure {
// structure definition goes here
}
class SomeClass {
// class definition goes here
}
舉個栗子:
//用于描述基于像素的顯示分辨率。此結(jié)構(gòu)有兩個存儲的屬性,稱為width和height。
struct Resolution {
var width = 0
var height = 0
}
?
//用于描述視頻顯示的特定視頻模式。
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
可以像下面這樣創(chuàng)建實例,以及訪問:
let someResolution = Resolution()
let someVideoMode = VideoMode()
?
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0"
?
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is 0"
?
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is now 1280"
這里需要了解的是,所有 結(jié)構(gòu)體 都有一個自動生成的成員初始化程序,可以使用它初始化新結(jié)構(gòu)實例的成員屬性:
let vga = Resolution(width: 640, height: 480)
而,類實例不接收默認(rèn)的成員初始值設(shè)定項。
其實,枚舉&結(jié)構(gòu)體 與 類 之間有一個很本質(zhì)的區(qū)別在于:枚舉&結(jié)構(gòu)體 是值類型,而 類 是引用類型。
枚舉&結(jié)構(gòu)體 是 值類型
首先,什么是 值類型 ?
值類型 是一種最簡單的類型,為什么這么說了?因為常見,比如各種語言里面的Int、Float、Double之流都是。
進(jìn)一步可以理解為 值類型 是一種沒有指針概念的類型。
那么問題來了,何為沒有指針概念呢?
從存儲上看可以這么理解:值類型 都是存放在 棧 中,而與之對應(yīng)的 引用類型 是在 棧 中存儲 指針,數(shù)據(jù)存在 堆 中,且棧中的指針指向?qū)?yīng)的數(shù)據(jù)的堆地址。
值得一說的是,Swift 中出了 枚舉、結(jié)構(gòu)體 是值類型,甚至連String,Array 以及 Dictionary 等都是值類型的。
為什么呢?因為 String,Array 以及 Dictionary其實都是通過 結(jié)構(gòu)體 實現(xiàn)的。
下面舉個栗子:
//實例化
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
//修改 width
cinema.width = 2048
?
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide"
?
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide"
當(dāng)cinema給出當(dāng)前值時hd,存儲的值hd被復(fù)制到新cinema實例中。最終結(jié)果是兩個完全獨立的實例,它們包含相同的數(shù)值。但是,因為它們是單獨的實例,所以設(shè)置寬度cinemato 2048不會影響存儲的寬度hd,內(nèi)存情況如下圖所示:

類 是 引用類型
引用類型,與值類型不同,引用類型 在分配給變量或常量時或者傳遞給函數(shù)時其值不會被復(fù)制。而不是副本,使用對同一現(xiàn)有實例的引用。
其實就是所謂的 淺拷貝 :只復(fù)制指針,而不復(fù)制其值;
換一種說法就是,淺拷貝 只是復(fù)制棧內(nèi)存,而指向同一塊兒堆內(nèi)存。
還是舉個栗子直觀的理解一下:
//實例化,VideoMode是上面定義的類,hd是上面實例化的實例
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
tenEighty分配一個名為的新常量alsoTenEighty,并alsoTenEighty修改幀速率:
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
?
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0"
內(nèi)存如下圖所示:

需要注意的是,tenEighty 并將 alsoTenEighty 其聲明為常量,而不是 變量。
但是,您仍然可以更改 tenEighty.frameRate,alsoTenEighty.frameRate,因為 tenEighty 和 alsoTenEighty 本身(棧中的指針)并未更改。tenEighty 并且 alsoTenEighty 他們自己不“存儲”VideoMode實例 ( VideoMode實例存儲在堆中)。
那么又一個來了,類 既然是引用類型,怎么判斷兩個實例是不是同一個呢?也就是說兩個不同的指針是不是指向同一塊堆內(nèi)存呢?
Swift 提供了一組操作符來方便的解決這個問題:===、!== 。
看著就很好理解舉個栗子:
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
以上。
喜歡我的可以關(guān)注收藏我的個人博客:Ro.bber