Swift3.x - 類和結構體

類的介紹和定義

  • Swift也是一門面向對象的開發語言。
  • 面向對象的基礎就是類,類產生對象。
  • Swift如何定義類:
    • class關鍵字定義類
    class 類名: SuperClass {
          //定義屬性和方法
    

}

* 使用注意:
* 定義類的時候,可以沒有父類,那么該類就是根類
* 通常情況下定義定義類時,繼承自NSObject

**如何定義類的屬性**
* Swift中類的屬性有多種:
* 存儲屬性:存儲實例的常量和變量
* 計算屬性:通過某種方式計算出來的屬性
* 類屬性:與整個類相關的屬性
* 存儲屬性
  ```
  class person: NSObject{
      //存儲屬性
      var age = 0
      var name: String?
  }

  let child = person()
  child.age = 18
  child.name = "小明"

  if let name = child.name {
      print("\(name)今年\(child.age)了")
  }
  //結果:小明今年18了
  ```
* 計算屬性
在類中聲明的計算屬性,這個屬性可以由類中定義的函數來完成,但是蘋果官方并不見這種實現方式,因為計算屬性的方式更加簡單明了,下面就來實現以下某個人的在某段時間內完成跑步的平均時速。

class person: NSObject{

  var time = 2
  var startSpeed = 10.0
  var hightSpeed = 20.0
  var endSpeed = 5.0

   //推薦
   var averageSpeed: Double {
       return (startSpeed + hightSpeed + endSpeed) * 0.5
   }
   //不推薦
   func averageSpeedFunction() -> Double {
      return (startSpeed + hightSpeed + endSpeed) * 0.5
  }

}

let child = person()
child.averageSpeedFunction()
child.averageSpeed

* 類屬性
類屬性是和整個類相關的屬性,而且是通過類名來訪問。常見于單例!

class person: NSObject{

  //定義某個人有書籍的數量
  static var book = 0

}

person.book = 2
//結果:2

**類的構造函數**
* 構造函數
  * 構造函數類似于OC中的初始化方法:init方法
  * 默認情況下創建某個類時,必然會調用一個構造函數
  * 即便開發者沒有構建構造函數,編譯器也會提供默認的構造函數
  * 如果繼承自NSObject可以對父類的構造函數進行重寫
* 構造函數的基本使用
  * 類的屬性必須有值
  * 如未在定義時初始化值,可以在構造函數中賦值,通過傳遞參數,初始化類對象。
      ```
      class person: NSObject{
  
          var name: String?
          var height = 0.0
          //重寫父類的構造方法
          //如果重寫父類的構造方法,在實例化此類時,Xcode會提示這個方法,如果未重寫,Xcode只會提示,我們自定義的構造方法!
          override init(){
              super.init()
          }
          //自定義構造方法
          init(name: String, height: Double) {
              self.name = name
              self.height = height
          }
  
      }

      let child = person(name: "小明", height: 1.88)
      child.name
      child.height
      //結果:小明 1.88
      ```
  * 通過字典參數實例化類對象
    ```
      class person: NSObject{
  
      var name: String?
      var height = 0.0
      //重寫父類的構造方法
      override init(){
           super.init()
      }
       //自定義構造方法
      init(name: String, height: Double) {
           self.name = name
           self.height = height
      }
  
      init(dict: [String : AnyObject]) {
             //此種寫法會報錯,因為從字典中取出的值為AnyObject?可選類型,直接賦值會報錯!
             //self.name = dict["name"]
             //self.height = dict["height"]

             //解決方法1:
             //as? 轉換符 將as?左側的類型轉換成as?右側的類型的可選類型
             name = dict["name"] as? String
             //as! 轉換符 將as!左側的類型轉換成as! 右側的類型的可選類型
             height = dict["height"] as! Double
             //但是此種寫法同時有帶來了新的問題,強制解包是很危險的操作,會造成程序crash
              
             //解決方法2:
             name = dict["name"] as? String
             //可選綁定
             if let tempHeight = dict["height"] as? Double {
                    height = tempHeight
             }
       }
      }
      let child = person(dict: ["name":"小明" as AnyObject, "height": 1.90 as AnyObject])
    ```
    利用KVC實現構造函數實現
    ```
        class person: NSObject{
  
        var name: String?
        var height = 0.0
        //重寫父類的構造方法
        override init(){
            super.init()
        }
        //自定義構造方法
        init(name: String, height: Double) {
            self.name = name
            self.height = height
        }
        //KVC
        init(dict: [String : AnyObject]) {
            super.init()
            setValuesForKeys(dict)
        }
        //防止傳入的字典存在未知的鍵值->報錯
        override func setValue(_ value: Any?, forUndefinedKey key: String) {}
    }
    let child = person(dict: ["name":"小明" as AnyObject, "height": 1.90 as AnyObject, "weight": 100 as AnyObject])
    child.name
    child.height
    //結果:小明 1.9
    ```

**類的屬性監聽器**
* 在OC中我們可以重寫set方法來監聽屬性的改變
* Swift中可以通過屬性觀察者來監聽和響應屬性的改變
* 通常監聽存儲屬性和類屬性
* 通過設置以下方法來定義觀察者
  * willSet:將在屬性值即將改變時調用
  * didSet:將在屬性值改變后調用
  class person: NSObject{

  var name: String?{
      willSet{
          print("\(name)")
      }
    
      didSet{
          print("\(name)")
      }
  }

}
let child = person()
child.name = "小明"


**結構體的介紹和定義**
結構體與類存在很多共同點:
* 定義屬性用于存儲值
* 定義方法用于提供功能
* 定義下標操作使得可以通過下標語法來訪問實例所包含的值
* 定義構造器用于生成初始化值
* 通過擴展以增加默認實現的功能
* 實現協議以提供某種標準功能

* Swift中如何定義結構體:
  * struct關鍵字定義結構體

struct 結構體名{
//結構體屬性or方法
}


**結構體實例化**
結構體實例化和類實例化非常相似:

struct SomeStruct{
//結構體屬性or方法
var width = 0
var height = 0
}
//實例化結構體
var someStruct = SomeStruct()

在Swift中,結構體可以直接修改結構體的子屬性的值,這點是與OC不同之處!

import UIKit

struct SomeStruct{
//結構體屬性or方法
var width = 0
var height = 0
}

var someStruct = SomeStruct()
someStruct.height = 100
someStruct.height
//結果:someStruct.height值為100

**結構體的逐一構造器**
結構體存在逐一構造器,而類中默認是不存在的!我們可以自定義構造函數來完成逐一構造器,上述類的自定義構造方法其實就是自定義的逐一構造器方法!

struct SomeStruct{
//結構體屬性or方法
var width = 0
var height = 0
}

var someStruct = SomeStruct(width: 66, height: 88)
someStruct.height
//結果:88
someStruct.width
//結果:66

**結構體與類之間的選擇**

?結構體總是通過值傳遞(值類型),類總是通過引用傳遞(引用類型)!
按照通用的準則,當符合一條或多條以下條件時,請考慮構建結構體:
* 該數據結構的主要目的是用來封裝少量相關簡單數據值。
* 有理由預計該數據結構的實例在被賦值或傳遞時,封裝的數據將會被拷貝而不是被引用。
* 該數據結構中儲存的值類型屬性,也應該被拷貝,而不是被引用。
* 該數據結構不需要去繼承另一個既有類型的屬性或者行為。

######注意:
在Swift中字符串、數組、字典均為結構體的形式實現(OC中均為類的形式實現)。拷貝行為看起來似乎總會發生。然而,Swift 在幕后只在絕對必要時才執行實際的拷貝。Swift 管理所有的值拷貝以確保性能最優化,所以你沒必要去回避賦值來保證性能最優化。

Zeb
參考地址:https://github.com/numbbbbb/the-swift-programming-language-in-chinese
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容