構造函數和析構函數

簡介

構造過程:結構體在和類在創建實例的過程中需要進行一些初始化工作,這個過程等稱之為構造過程
析構過程:類和結構體在最后被釋放的時候需要進行一些釋放資源的操作,這個過程稱之為析構過程

構造函數

類和結構體的實例在構造過程中會調用一種特殊的init方法,稱之為構造函數。構造函數沒有返回值,可以重載。多個構造函數重載的情況下,運行環境會根據它的參數標簽或者是參數列表調用合適的構造函數。

  1. 默認構造函數
    如果我們沒有編寫任何的構造函數,類和結構體會提供一個默認的構造函數。下面的例子中,rect的初始化就調用了默認的構造函數
class Rectangle {
    var width: Double = 0.0
    var height: Double = 0.0
}
var rect = Rectangle()
rect.height = 1.0
rect.width = 2.0

類和結構體的默認構造函數有所不同,結構體的默認構造函數可以按照從上到下的順序把屬性名作為參數標簽,依次提供參數,代碼示例如下:

struct Rectangle {  
  var width: Double
    var height: Double
    //默認構造函數實現
    init(width: Double, height: Double) {
        self.width = width;
        self.height = height;
    }
}
var rect = Rectangle.init(width: <#T##Double#>, height: <#T##Double#>)
  1. 構造函數與存儲屬性初始化
    構造函數的主要作用就是初始化實例,其中包括存儲屬性和其他屬性的初始化。(在不聲明為可選類型的情況下,如果存儲屬性在構造函數中沒有初始化,在定義的時候也沒有初始化,那么就會發生編譯錯誤)如下:


    屏幕快照 2017-12-24 下午3.07.19.png

    所以我們在創建一個類或者是結構體的時候,存儲屬性如果沒有初初始化,需要初始化存儲屬性:

class Rectangle {
    let num: Int
    var width: Double = 0.0
    var height: Double
    var name: String?
    
    init() {
        self.num = 5
        self.height = 0.0
        self.name = "haha"
    }   
}

注意:常量類型只能在定義的時候賦值,而在構造函數中,常量類型可以不遵守這個規則。在別的方法中不行。另外,如果我們在定義的時候不能確定存儲屬性的值,可以將其聲明為可選類型。

  1. 使用參數標簽
    為了增強程序的可讀性,swift在方法和函數中可以使用參數標簽。例如:
class Rectangle {
    var width: Double
    var height: Double
    
    init(W width: Double, H height: Double) {
        self.width = width
        self.height = height
    }
    
}
var rect = Rectangle.init(W: <#T##Double#>, H: <#T##Double#>)
//如果沒有聲明參數標簽,參數名會直接作為參數標簽使用
var rect = Rectangle.init(width: <#T##Double#>, height: <#T##Double#>)

一般情況下訪問屬性時self可以省略,但是局部變量和常量命名與屬性名發生沖突的時候,屬性前面一定要加上self

  1. 構造函數重載
    swift中的構造函數可以有多個,但是它們的參數列表不同,這些構造函數構成重載
class Rectangle {
    var width: Double
    var height: Double
    
    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
    init(W width: Double, H height: Double) {
        self.width = width
        self.height = height
    }
}

上面代碼中,兩個構造函數就是重載關系,雖然他們的功能是一樣的,但是他們的參數列表不同(參數標簽不同)

構造函數代理

為了減少多個構造函數之間的代碼重復,在定義構造函數時可以通過調用其他構造函數來完成實例的部分構造過程,這個過程稱之為構造函數代理。構造函數代理在結構體和類中的使用方式不同。

結構體構造函數代理

struct Rectangle {
    var width: Double
    var height: Double
    
    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
    init(W width: Double, H height: Double) {
        self.init(width: width, height: height)
    }
    init() {
        self.init(width: 1.0, height: 2.0)
    }
}

類構造函數代理

由于類有繼承關系,所以類構造函數代理分為橫向代理和向上代理

橫向代理類似于結構體類型構造函數代理,發生在同一類內部,這種構造函數稱之為便利構造函數
向上代理發生在繼承情況下,在子類構造過程中要先調用父類構造函數,初始化父類的存儲屬性,這種構造函數稱為指定構造函數

橫向代理如下

class Rectangle {
    var width: Double
    var height: Double
    
    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
    convenience init(W width: Double, H height: Double) {
        self.init(width: width, height: height)
    }
    convenience init() {
        self.init(width: 1.0, height: 2.0)
    }
}

convenience表示遍歷構造函數,這說明我們定義的構造函數時橫向代理調用其他構造函數

向上代理

析構函數

與構造過程相反,實例在最后釋放的時候需要清除一些資源,這個過程就是析構過程,析構過程也會調用一個特殊的方法 deinit ,成為析構函數。析構函數沒有返回值,也沒有參數,也不需要參數的小括號,所以不能重載。(析構函數只適用于類,不適用于枚舉和結構體)

class Test {
    var width: Double
    var height: Double
    
    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
    convenience init(W width: Double, H height: Double) {
        self.init(width: width, height: height)
    }
    convenience init() {
        self.init(width: 1.0, height: 2.0)
    }
    deinit {
        print("調用析構函數")
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容