前言
-
Swift 語言有兩種基本的數據類型,即類(class)和結構體(struct),class 這樣的概念大家不會陌生,而 struct 也並不是什么新的概念,在 Objective-C 和 C 中也有 struct,不過 Swift 將 struct 提升到一個更高更重要的層次,甚至 Swift Foundation 框架的 SDK,諸如
String,Array,Dictionary
都是基於 struct 實現的。 -
結構體是由一系列具有相同類型或不同類型的數據構成的數據集合。
-
和 class 一樣,struct 也可以定義屬性和方法,同樣 struct 也要求完整初始化,即保證初始化過程中每一個 non-optional 屬性要賦予明確的初始值。
-
結構體是值類型,並且只有在賦予變量或常量,或者被函數調用時才被賦值。
1、結構體的創建
-
結構體基本結構
struct 結構體名 { var 或 let 字段名 = 初始化值 var 或 let 字段名: 類型 }
struct Student { var age = 0 } var stu = Student() /// struct 結構體關鍵字 /// Student 結構體名稱 /// student() 創建一個結構體變量
1.1 標准定義
-
結構體的定義
-
定義結構體字段時可以直接定義一個字段名,並且給字段名賦初始值。或者只定義一個字段名,不賦初始值,但是不賦初始值的字段在創建結構體變量時必須賦初始值。
struct Student { var name: String // 只定義一個字段名,不賦初始值 var age = 0 // 定義一個字段名,並且給字段名賦初始值 }
-
-
結構體的使用
-
創建結構體變量時,結構體的字段都必須都有初始值,否則會報錯。
let s = Student(name: "appple", age: 8) // 創建結構體變量時初始化結構體的字段 print("\(s.name), \(s.age)") // 結構體類型變量值的調用
-
1.2 基本定義
-
結構體的定義
-
每個字段名都賦初始值。
struct BookInfo { var id: Int = 0 // 每個字段名都賦初始值 var name: String = "Default" var author: String = "Default" var rootType: String = "Default" }
-
-
結構體的使用
-
創建結構體變量時,結構體的字段都必須都有初始值,否則會報錯。
let book = BookInfo() // 創建結構體變量時不再需要初始化結構體的字段 print("\(book.id), \(book.name), \(book.author), \(book.rootType)") // 結構體類型變量值的調用
-
2、結構體的方法
2.1 定義枚舉的方法
-
枚舉方法的定義
struct markStruct1 { var mark1: Int = 0 var mark2: Int = 0 var mark3: Int = 0 func sum(a: Int) -> Int { // 定義方法 return (self.mark1 + self.mark2 + self.mark3) * a } }
-
枚舉方法的使用
let mark1 = markStruct1(mark1: 11, mark2: 22, mark3: 33) print(mark1.sum(a: 2)) // print 132
2.2 自定義構造方法
-
與 class 的初始化方法不同點
- struct 的 init 並沒有便利初始化(convenience init)方法。
- 因為 struct 沒有繼承,所以 struct 的 init 也不需要 required 關鍵字。
-
這樣對比,struct 的初始化方法比起 class 的初始化方法來說要簡單的多,因為 struct 只有指定初始化,struct 只需要保證指定初始化過程中每個非可選屬性都賦值,沒有復雜的初始化規則和規范,struct 相比於 class 也顯得更加簡單,更有親和力。
-
一旦我們自定義了初始化器,系統自動的初始化器就不起作用了,如果還需要使用到系統提供的初始化器,在我們自定義初始化器后就必須顯式的定義出來。
-
可失敗構造方法
struct markStruct2 { var mark1: Int var mark2: Int var mark3: Int init?(mark1: Int, mark2: Int, mark3: Int) { // 可失敗(failable)的構造方法 self.mark1 = mark1 self.mark2 = mark2 self.mark3 = mark3 } }
-
普通構造方法
struct markStruct3 { var mark1: Int var mark2: Int var mark3: Int init(mark1: Int, mark2: Int, mark3: Int) { // 普通的構造方法 self.mark1 = mark1 self.mark2 = mark2 self.mark3 = mark3 } }
-
使用
let mark2 = markStruct2(mark1: 11, mark2: 22, mark3: 33) print("\(mark2?.mark1 ?? 0), \(mark2?.mark2 ?? 0), \(mark2?.mark3 ?? 0)") // print 11, 22, 33 let mark3 = markStruct3(mark1: 11, mark2: 22, mark3: 33) print("\(mark3.mark1), \(mark3.mark2), \(mark3.mark3)") // print 11, 22, 33
3、Swift 中枚舉、結構體和類的比較
3.1 在 Swift 中類型引用和值引用的區別
-
對於類型引用(class reference),將變量
a
賦值給變量b
,即b = a
,這樣的賦值語句僅僅將b
的指針與a
的指針一樣,指向同一塊內存區域,此時改變b
的值,a
也會跟着改變; -
對於值引用(value reference),賦值語句
b = a
處理的過程是開辟一個新的內存b
,將a
變量的內容拷貝后存放到內存b
,這時a
和b
完全沒有關系的兩個變量,對b
的改變不會影響到a
,反之亦然。 -
在 Objective-C 時代,我們對類型引用和值引用就有了一定的了解,例如在 Objective-C 中常用的
NSArray, NSDictionary, NSString, UIKit
等都是類型引用;而NSInteger, CGFloat, CGRect
等則是值引用。 -
顯然,在 Objective-C 中,引用類型占據了很大的比重,現在使用 Swift 開發應用程序,開發者需要轉變觀念,因為 struct 在 Swift 變得越來越重要,觀念的轉變不僅在於多使用 struct,還要求開發者理解 struct 的原理,優點及缺點。
3.2 枚舉、結構體、類的共同點
- 定義屬性用於存儲值,枚舉只能定義計算屬性
- 定義方法以提供功能
- 定義下標,以便用下標語法來訪問它們的值
- 定義初始化程序,以創建它們的初始狀態
- 支持擴展增加功能,來擴展它們的默認實現
- 可以遵循協議,來完成特定標准功能
3.3 枚舉、結構體、類的區別
- 類是引用類型,而枚舉和結構體是值類型
- 類有繼承功能,而枚舉和結構體沒有繼承的功能
3.4 類特有的功能
- 繼承
- 允許類型轉換
- 析構方法釋放資源
- 引用計數
3.5 該如何選擇
-
關於在新建一個類型時如何選擇到底是使用值類型還是引用類型的問題其實在理解了兩者之間的區別后是非常簡單的,在這蘋果官方已經做出了非常明確的指示
- 當你使用 Cocoa 框架的時候,很多 API 都要通過
NSObject
的子類使用,所以這時候必須要用到引用類型 class。 - 在其他情況下,有下面幾個准則。
- 當你使用 Cocoa 框架的時候,很多 API 都要通過
-
1)什么時候該用值類型
- 要用
==
運算符來比較實例的數據時 - 你希望那個實例的拷貝能保持獨立的狀態時
- 數據會被多個線程使用時
- 要用
-
2)什么時候該用引用類型(class)
- 要用
==
運算符來比較實例身份的時候 - 你希望有創建一個共享的、可變對象的時候
- 要用