Swift構造函數和便利構造函數

来源:http://www.cnblogs.com/evening015/archive/2016/04/04/5351740.html
-Advertisement-
Play Games

構造函數基礎 構造函數是一種特殊的函數,主要用來在創建對象時初始化對象,為對象成員變數設置初始值,在 OC 中的構造函數是 initWithXXX,在 Swift 中由於支持函數重載,所有的構造函數都是 init 構造函數的作用 分配空間 alloc 設置初始值 init 必選屬性 自定義 Pers ...


構造函數基礎

構造函數是一種特殊的函數,主要用來在創建對象時初始化對象,為對象成員變數設置初始值,在 OC 中的構造函數是 initWithXXX,在 Swift 中由於支持函數重載,所有的構造函數都是 init

構造函數的作用

  • 分配空間 alloc
  • 設置初始值 init

必選屬性

  • 自定義 Person 對象
class Person: NSObject {

    /// 姓名
    var name: String
    /// 年齡
    var age: Int
}

提示錯誤 Class 'Person' has no initializers -> 'Person' 類沒有實例化器s

原因:如果一個類中定義了必選屬性,必須通過構造函數為這些必選屬性分配空間並且設置初始值

  • 重寫 父類的構造函數
/// `重寫`父類的構造函數
override init() {

}

提示錯誤 Property 'self.name' not initialized at implicitly generated super.init call -> 屬性 'self.name' 沒有在隱式生成的 super.init 調用前被初始化

  • 手動添加 super.init() 調用
/// `重寫`父類的構造函數
override init() {
    super.init()
}

提示錯誤 Property 'self.name' not initialized at super.init call -> 屬性 'self.name' 沒有在 super.init 調用前被初始化

  • 為必選屬性設置初始值
/// `重寫`父類的構造函數
override init() {
    name = "張三"
    age = 18

    super.init()
}

小結

  • 非 Optional 屬性,都必須在構造函數中設置初始值,從而保證對象在被實例化的時候,屬性都被正確初始化
  • 在調用父類構造函數之前,必須保證本類的屬性都已經完成初始化
  • Swift 中的構造函數不用寫 func

子類的構造函數

  • 自定義子類時,需要在構造函數中,首先為本類定義的屬性設置初始值
  • 然後再調用父類的構造函數,初始化父類中定義的屬性
/// 學生類
class Student: Person {

    /// 學號
    var no: String

    override init() {
        no = "001"

        super.init()
    }
}

小結

  • 先調用本類的構造函數初始化本類的屬性
  • 然後調用父類的構造函數初始化父類的屬性
  • Xcode 7 beta 5之後,父類的構造函數會被自動調用,強烈建議寫 super.init(),保持代碼執行線索的可讀性
  • super.init() 必須放在本類屬性初始化的後面,保證本類屬性全部初始化完成

Optional 屬性

  • 將對象屬性類型設置為 Optional
class Person: NSObject {
    /// 姓名
    var name: String?
    /// 年齡
    var age: Int?
}
  • 可選屬性不需要設置初始值,預設初始值都是 nil
  • 可選屬性是在設置數值的時候才分配空間的,是延遲分配空間的,更加符合移動開發中延遲創建的原則

重載構造函數

  • Swift 中支持函數重載,同樣的函數名,不一樣的參數類型
/// `重載`構造函數
///
/// - parameter name: 姓名
/// - parameter age:  年齡
///
/// - returns: Person 對象
init(name: String, age: Int) {
    self.name = name
    self.age = age

    super.init()
}

註意事項

  • 如果重載了構造函數,但是沒有實現預設的構造函數 init(),則系統不再提供預設的構造函數
  • 原因,在實例化對象時,必須通過構造函數為對象屬性分配空間和設置初始值,對於存在必選參數的類而言,預設的 init() 無法完成分配空間和設置初始值的工作

調整子類的構造函數

  • 重寫父類的構造函數
/// `重寫`父類構造函數
///
/// - parameter name: 姓名
/// - parameter age:  年齡
///
/// - returns: Student 對象
override init(name: String, age: Int) {
    no = "002"

    super.init(name: name, age: age)
}
  • 重載構造函數
/// `重載`構造函數
///
/// - parameter name: 姓名
/// - parameter age:  年齡
/// - parameter no:   學號
///
/// - returns: Student 對象
init(name: String, age: Int, no: String) {
    self.no = no

    super.init(name: name, age: age)
}

註意:如果是重載的構造函數,必須 super 以完成父類屬性的初始化工作

重載重寫

  • 重載,函數名相同,參數名/參數個數不同
    • 重載函數並不僅僅局限於構造函數
    • 函數重載是面相對象程式設計語言的重要標誌
    • 函數重載能夠簡化程式員的記憶
    • OC 不支持函數重載,OC 的替代方式是 withXXX...
  • 重寫,子類需要在父類擁有方法的基礎上進行擴展,需要 override 關鍵字

KVC 字典轉模型構造函數

/// `重寫`構造函數
///
/// - parameter dict: 字典
///
/// - returns: Person 對象
init(dict: [String: AnyObject]) {
    setValuesForKeysWithDictionary(dict)
}
  • 以上代碼編譯就會報錯!
  • 原因:

    • KVC 是 OC 特有的,KVC 本質上是在運行時,動態向對象發送 setValue:ForKey: 方法,為對象的屬性設置數值
    • 因此,在使用 KVC 方法之前,需要確保對象已經被正確實例化
  • 添加 super.init() 同樣會報錯

  • 原因:

    • 必選屬性必須在調用父類構造函數之前完成初始化分配工作
  • 將必選參數修改為可選參數,調整後的代碼如下:

/// 個人模型
class Person: NSObject {

    /// 姓名
    var name: String?
    /// 年齡
    var age: Int?

    /// `重寫`構造函數
    ///
    /// - parameter dict: 字典
    ///
    /// - returns: Person 對象
    init(dict: [String: AnyObject]) {
        super.init()

        setValuesForKeysWithDictionary(dict)
    }
}

運行測試,仍然會報錯

錯誤信息:this class is not key value coding-compliant for the key age. -> 這個類的鍵值 age 與 鍵值編碼不相容

  • 原因:
    • 在 Swift 中,如果屬性是可選的,在初始化時,不會為該屬性分配空間
    • 而 OC 中基本數據類型就是保存一個數值,不存在可選的概念
  • 解決辦法:給基本數據類型設置初始值
  • 修改後的代碼如下:
/// 姓名
var name: String?
/// 年齡
var age: Int = 0

/// `重寫`構造函數
///
/// - parameter dict: 字典
///
/// - returns: Person 對象
init(dict: [String: AnyObject]) {
    super.init()

    setValuesForKeysWithDictionary(dict)
}

提示:在定義類時,基本數據類型屬性一定要設置初始值,否則無法正常使用 KVC 設置數值

KVC 函數調用順序

init(dict: [String: AnyObject]) {
    super.init()

    setValuesForKeysWithDictionary(dict)
}

override func setValue(value: AnyObject?, forKey key: String) {
    print("Key \(key) \(value)")

    super.setValue(value, forKey: key)
}

// `NSObject` 預設在發現沒有定義的鍵值時,會拋出 `NSUndefinedKeyException` 異常
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
    print("UndefinedKey \(key) \(value)")
}
  • setValuesForKeysWithDictionary 會按照字典中的 key 重覆調用 setValue:forKey 函數
  • 如果沒有實現 forUndefinedKey 函數,程式會直接崩潰
    • NSObject 預設在發現沒有定義的鍵值時,會拋出 NSUndefinedKeyException 異常
  • 如果實現了 forUndefinedKey,會保證 setValuesForKeysWithDictionary 繼續遍歷後續的 key
  • 如果父類實現了 forUndefinedKey,子類可以不必再實現此函數

子類的 KVC 函數

/// 學生類
class Student: Person {

    /// 學號
    var no: String?
}
  • 如果父類中已經實現了父類的相關方法,子類中不用再實現相關方法

convenience 便利構造函數

  • 預設情況下,所有的構造方法都是指定構造函數 Designated
  • convenience 關鍵字修飾的構造方法就是便利構造函數
  • 便利構造函數具有以下特點:
    • 可以返回 nil
    • 只有便利構造函數中可以調用 self.init()
    • 便利構造函數不能被重寫或者 super
/// `便利構造函數`
///
/// - parameter name: 姓名
/// - parameter age:  年齡
///
/// - returns: Person 對象,如果年齡過小或者過大,返回 nil
convenience init?(name: String, age: Int) {
    if age < 20 || age > 100 {
        return nil
    }

    self.init(dict: ["name": name, "age": age])
}

註意:在 Xcode 中,輸入 self.init 時沒有智能提示

/// 學生類
class Student: Person {

    /// 學號
    var no: String?

    convenience init?(name: String, age: Int, no: String) {
        self.init(name: name, age: age)

        self.no = no
    }
}

便利構造函數應用場景

  • 根據給定參數判斷是否創建對象,而不像指定構造函數那樣必須要實例化一個對象出來
  • 在實際開發中,可以對已有類的構造函數進行擴展,利用便利構造函數,簡化對象的創建

構造函數小結

  • 指定構造函數必須調用其直接父類的的指定構造函數(除非沒有父類)
  • 便利構造函數必須調用同一類中定義的其他指定構造函數或者用 self. 的方式調用父類的便利構造函數
  • 便利構造函數可以返回 nil
  • 便利構造函數不能被重寫


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一般來說傳圖片可以以流的形式來傳輸,即便是用json傳輸,一般也都是傳一個地址,而圖片都存在伺服器上,然後順著地址發送請求下載圖片。 但是這次公司的項目中,圖片是存在oracle資料庫中的blob欄位的,並沒有存在伺服器上,也就是說我必須傳圖片本身過去,而json是無法傳輸二進位的文本格式,因此我就 ...
  • 官方定義: Swoole:重新定義PHP PHP的非同步、並行、高性能網路通信引擎,使用純C語言編寫,提供了PHP語言的非同步多線程伺服器,非同步TCP/UDP網路客戶端,非同步MySQL,非同步Redis,資料庫連接池,AsyncTask,消息隊列,毫秒定時器,非同步文件讀寫,非同步DNS查詢。 Swoole內 ...
  • 1.org.apache.catalina.servlets.DefaultServlet 首先所有的請求進入tomcat,都會流經servlet,如果沒有匹配到任何應用指定的servlet,那麼就會流到預設的servlet。預設的servlet是配置在/conf/web.xml裡面的。配置文件中被 ...
  • Activiti的設計編輯器功能 Create Activiti projects and diagrams. 創建Activiti的項目和圖表。 The Activiti Designer creates a .bpmn file when creating a new Activiti diag ...
  • 前一篇已經翻譯過termvectors的使用方法了,這對於學習如何使用tf idf來說是很有幫助的了。 更多內容參考 "我整理的ELK教程" 什麼是TF IDF? 今天早晨起來,看《ES IN ACTION》的時候,遇到了這個術語,看英文實在不明白,於是百度了一下。看到了阮一峰的一篇關於它的文章,講 ...
  • Java虛擬機位元組碼指令 瞭解了class文件,我覺得就很有必要去瞭解一下JVM中的位元組碼指令,那樣堆class文件以及JVM運行機制也後很大的幫助. Java虛擬機的指令由一個位元組長度的,代表著某種特定操作含義的數字(稱為操作碼,Opcode)以及跟隨其後的零至多個代表所需參數(稱為操作數,Opr ...
  • 一.String類概述 1.String的值是一個對象,也是一個常量不能被改變 2.String的equals方法是比較兩個字元串的內容 3.String s1=”abc” String s2=new String(“abc”) s1有一個對象,s2有兩個對象 二.String常見功能 獲取和判斷 ...
  • 屬性表集合 在前面魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引,介面索引集合,欄位表集合,方法表集合,那麼接下來就是屬性表集合了. 屬性表集合 在前面魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引,介面索引集合,欄位表集合,方法表集合,那麼接下來 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...