(二十一)[Swift]Swift中的init方法

[Swift]Swift中的init方法

1.說明

  • Struct中的init的機制和class的基本類似,不同點我在 中也已經(jīng)說明
  • 本文以Class的init方法為例

2.designated init

class 中所有的成員變量在對象創(chuàng)建時必須有一個初始值

所以下面這種形式無法通過編譯

class Point2D{
    var x : Double
    var y : Double
}

修改方式1:為成員變量加上一個默認(rèn)值

class Point2D{
    var x:Double = 1.0
    var y:Double = 1.0
}

這樣就有一個默認(rèn)的無參的init方法

let p = Point2D()

//修改方式2:為class加上一個designated init方法

即在此方法中將所有的沒有默認(rèn)值的員變量初始化

class Point2D2{
    var x:Double
    var y:Double
    init(x:Double,y:Double){
        self.x = x
        self.y = y
    }
}

這樣就有一個有兩個參數(shù)的init方法,而默認(rèn)的無參的init方法,已經(jīng)沒有了

// let p2 = Point2D2() //錯誤
let p21 = Point2D2(x:1,y:1)

其實這樣要把所有沒有默認(rèn)值的成員變量初始化的init方法跟我博客中 全能初始化方法 這章提到的全能初始化方法比較類似

3.convenience init 方法

除了有designated init方法,一個類中還可以設(shè)定convenience init方法來方便初始化

比如

class Point2D3{
    var x:Double
    var y:Double
    init(x:Double,y:Double){
        self.x = x
        self.y = y
    }
    convenience init(xStr:String,yStr:String){
        let x = Double(xStr)
        let y = Double(yStr)
        self.init(x:x!,y:y!)
    }
    convenience init(xy:(Double,Double)){
        let x = xy.0
        let y = xy.1
        self.init(x:x,y:y)
    }
}

這樣我們就有多種方式創(chuàng)建這個類的對象

let p3 = Point2D3(x:1,y:1)
let p31 = Point2D3(xStr: "1",yStr: "1")
let p32 = Point2D3(xy:(1,1))

但是通過字符串創(chuàng)建很可能會出現(xiàn)問題

//let p34 = Point2D3(xStr: "aaa",yStr: "1")
//error :fatal error: unexpectedly found nil while unwrapping an Optional value

4.failable init方法,即有允許初始化失敗時返回nil

class Point2D4{
    var x:Double
    var y:Double
    init(x:Double,y:Double){
        self.x = x
        self.y = y
    }
    convenience init?(xStr:String,yStr:String){
        let x = Double(xStr)
        let y = Double(yStr)
        if x == nil || y == nil{
            return nil
        }
        self.init(x:x!,y:y!)
    }

}

failable init 還可以是designated init方法

以前返回nil的語句應(yīng)該放在成員變量初始化之后,經(jīng)測試,現(xiàn)在沒有了這個限制

class Point2D5{
    var x:Double
    var y:Double
//    init?(x:Double,y:Double){
//        self.x = x
//        self.y = y
//        if(x < 0 || y < 0 ){
//            return nil
//        }
//    }
    init?(x:Double,y:Double){
        if(x < 0 || y < 0 ){
            return nil
        }
        self.x = x
        self.y = y
    }
    
}

這樣我們創(chuàng)建失敗后就不會報錯,會是一個nil,

但是請注意,這樣創(chuàng)建出來的對象是一個optional對象

let p4 = Point2D4(xStr: "aaa",yStr: "1")
p4 //nil
let p41 = Point2D4(xStr: "1",yStr: "1")
p41 //1,1
let p5 = Point2D5(x:1,y:-1)

p4.dynamicType  //Optional<Point2D4>.Type
p5.dynamicType  //Optional<Point2D5>.Type


5.初始化自身屬性時需要self作為參數(shù)傳遞給屬性的初始化參數(shù)

class City{
    var country : Country
    init(country:Country){
        self.country = country;
    }
}
class Country {
    var capital : City
    init(){
        //編譯器認(rèn)為本對象的capital還沒初始化完,不能使用self
        //而初始化capital又必須使用self
        //每個國家必須有一個首都,captial屬性也不能設(shè)置為optional
        //所以需要把capital設(shè)置為implicitly unwrapped Optional,這樣,編譯器就認(rèn)為capital已經(jīng)被初始化過,初始化值為nil
        self.capital = City(country:self) //報錯
    }
}

所以Country類應(yīng)該修改為這樣

class Country {
    var capital : City!
    init()
        self.capital = City(country:self) //正確
    }
}

6.屬性是一個使用self變量的closure

class HTMLElement{
    var text:String
    init(text:String){
        self.text=text
    }
    var asHTML : Void -> String = {
        return "<text>\(self.text)</text>"
    } //error: use of unresolved identifier 'self'
}

編譯器無法識別closure中的self屬性,所以這個時候應(yīng)該使用lazy property

class HTMLElement{
    var text:String
    init(text:String){
        self.text=text
    }
    lazy var asHTML : Void -> String = {
        return "<text>\(self.text)</text>"
    } 
}

這樣就不會報錯,但是這樣還是會有循環(huán)引用的問題,關(guān)于這個問題,我在第24篇中有詳細(xì)描述

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容