與其他編程語言所不同的是,Swift 並不要求你為自定義類和結構去創建獨立的介面和實現文件。你所要做的是在一個單一文件中定義一個類或者結構體,系統將會自動生成面向其它代碼的外部介面。 註意:通常一個類的實例被稱為對象。然而在Swift 中,類和結構體的關係要比在其他語言中更加的密切,本章中所討論的大 ...
與其他編程語言所不同的是,Swift 並不要求你為自定義類和結構去創建獨立的介面和實現文件。你所要做的是在一個單一文件中定義一個類或者結構體,系統將會自動生成面向其它代碼的外部介面。
註意:通常一個類的實例被稱為對象。然而在Swift 中,類和結構體的關係要比在其他語言中更加的密切,本章中所討論的大部分功能都可以用在類和結構體上。因此,我們會主要使用實例而不是對象。
比較類和結構體
類和結構體都具有以下特性:
- 定義用於存儲值的屬性
- 定義提供特定能力或功能的方法
- 定義提供使用下標語法訪問值的下標
- 定義設置初始狀態的初始化方法
- 通過擴展以增加預設實現的功能
- 符合協議提供某種標準功能
類還具有結構體沒有的功能,如下:
- 繼承使一個類具有另一個類的特性
- 類型轉換允許在運行時檢查和解釋一個類實例的類型
- 反初始化允許一個類實例釋放任何其所被分配的資源
- 引用計數允許對一個類的多次引用
註意:結構體總是通過被覆制的方式在代碼中傳遞,因此請不要使用引用計數。
定義語法
使用class關鍵字來申明一個類,使用struct關鍵字來申明一個結構體。
class SomeClass {
}
struct SomeStructure {
}
註意:類和結構體名稱以大寫字母開頭,屬性和方法名稱以小寫字母開頭。
示例如下
struct Resolution { var width = 0 var heigth = 0 } class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
在上面的示例中我們定義了一個名為Resolution的結構體,用來描述一個顯示器的像素解析度。這個結構體包含了兩個名為width和height的儲存屬性。儲存屬性是捆綁和儲存在類或結構體中的常量或變數。當這兩個屬性被初始化為整數0的時候,它們會被推斷為Int類型。個名為VideoMode的類,用來描述一個視頻顯示器的特定模式。這個類包含了四個儲存屬性變數。第一個是解析度,它被初始化為一個新的Resolution結構體的實例,具有Resolution的屬性類型。新VideoMode實例同時還會初始化其它三個屬性,它們分別是,初始值為false(意為“non-interlaced video”)的inteflaced,回放幀率初始值為0.0的frameRate和值為可選String的name。name屬性會被自動賦予一個預設值nil,意為“沒有name值”,因它是一個可選類型。
類和結構體實例
Resolution結構體和VideoMode類的定義僅描述了什麼是Resolution和VideoMode。它們並沒有描述一個特定的解析度(resolution)或者視頻模式(video mode)。為了描述一個特定的解析度或者視頻模式,我們需要創建一個它們的實例。如下
let someResolution = Resolution()
let someVideoMode = VideoMode()
過這種方式所創建的類或者結構體實例,其屬均會被初始化為預設值。
屬性訪問
使用點語法訪問實例中所含有的屬性。其語法規則是,實例名後面緊跟屬性名,兩者通過點號(.)連接:
println("The width of someResolution is \(someResolution.width)")
你也可以訪問子屬性,如何VideoMode中Resolution屬性的width屬性:
println("The width of someVideoMode is \(someVideoMode.resolution.width)")
你也可以使用點語法為屬性變數賦值
someVideoMode.resolution.width = 12880
println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
註意:與 Objective-C 語言不同的是,Swift 允許直接設置結構體屬性的子屬性。上面的最後一個例子,就是直接設置了someVideoMode中resolution屬性的width這個子屬性,以上操作並不需要從新設置resolution屬性。
逐個成員初始化器的結構類型
所有結構體都有一個自動生成的成員逐一初始化方法,用於初始化新結構體實例中成員的屬性。新實例中各個屬性的初始值可以通過屬性的名稱傳遞到成員逐一初始化器之中:
let vga = resolution(width:640, heigth: 480)
與結構體不同,類實例沒有預設的成員逐一初始化器。
結構體和枚舉是值類型
個值類型是一個值,當它被分配給一個變數或常量時,或當它被傳遞給函數時,它的值是被覆制的,這意味著它們的實例,以及實例中所包含的任何值類型屬性,在代碼中傳遞的時候都會被覆制。
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
在以上示例中,聲明瞭一個名為hd的常量,其值為一個初始化為全高清視頻解析度(1920 像素寬,1080 像素高)的Resolution實例。
然後示例中又聲明瞭一個名為cinema的變數,其值為之前聲明的hd。因為Resolution是一個結構體,所以cinema的值其實是hd的一個拷貝副本,而不是hd本身。儘管hd和cinema有著相同的寬(width)和高(height)屬性,但是在後臺中,它們是兩個完全不同的實例。
類是引用類型
與值類型不同,引用類型在被賦予到一個變數,常量或者被傳遞到一個函數時,操作的並不是其拷貝。因此,引用的是已存在的實例本身而不是其拷貝
恆等運算符
因為類是引用類型,有可能有多個常量和變數在後臺同時引用某一個類實例。如果能夠判定兩個常量或者變數是否引用同一個類實例將會很有幫助。為了達到這個目的,Swift 內建了兩個恆等運算符:
等價於 ( === )
不等價於 ( !== )
if tenEighty === alsoTenTighty { println("tenTighty and alsoTenEighty refer to the same Resolution instance.") }
指針
如果你有 C,C++ 或者 Objective-C 語言的經驗,那麼你也許會知道這些語言使用指針來引用記憶體中的地址。一個 Swift 常量或者變數引用一個引用類型的實例與C語言中的指針類似,不同的是並不直接指向記憶體中的某個地址,而且也不要求你使用星號(*)來表明你在創建一個引用。Swift 中這些引用與其它的常量或變數的定義方式相同。