[Swift]Swift中的init方法
1.说明
- Struct中的init的机制和class的基本类似,不同点我在 中也已经说明
- 本文以Class的init方法为例
2.designated init
class 中所有的成员变量在对象创建时必须有一个初始值
所以下面这种形式无法通过编译
class Point2D{
var x : Double
var y : Double
}
修改方式1:为成员变量加上一个默认值
class Point2D{
var x:Double = 1.0
var y:Double = 1.0
}
这样就有一个默认的无参的init方法
let p = Point2D()
//修改方式2:为class加上一个designated init
方法
即在此方法中将所有的没有默认值的员变量初始化
class Point2D2{
var x:Double
var y:Double
init(x:Double,y:Double){
self.x = x
self.y = y
}
}
这样就有一个有两个参数的init方法,而默认的无参的init方法,已经没有了
// let p2 = Point2D2() //错误
let p21 = Point2D2(x:1,y:1)
其实这样要把所有没有默认值的成员变量初始化的init方法跟我博客中 全能初始化方法 这章提到的全能初始化方法比较类似
3.convenience init 方法
除了有designated init方法,一个类中还可以设定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)
}
}
这样我们就有多种方式创建这个类的对象
let p3 = Point2D3(x:1,y:1)
let p31 = Point2D3(xStr: "1",yStr: "1")
let p32 = Point2D3(xy:(1,1))
但是通过字符串创建很可能会出现问题
//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的语句应该放在成员变量初始化之后,经测试,现在没有了这个限制
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
}
}
这样我们创建失败后就不会报错,会是一个nil,
但是请注意,这样创建出来的对象是一个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作为参数传递给属性的初始化参数
class City{
var country : Country
init(country:Country){
self.country = country;
}
}
class Country {
var capital : City
init(){
//编译器认为本对象的capital还没初始化完,不能使用self
//而初始化capital又必须使用self
//每个国家必须有一个首都,captial属性也不能设置为optional
//所以需要把capital设置为implicitly unwrapped Optional,这样,编译器就认为capital已经被初始化过,初始化值为nil
self.capital = City(country:self) //报错
}
}
所以Country类应该修改为这样
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属性,所以这个时候应该使用lazy property
class HTMLElement{
var text:String
init(text:String){
self.text=text
}
lazy var asHTML : Void -> String = {
return "<text>\(self.text)</text>"
}
}
这样就不会报错,但是这样还是会有循环引用的问题,关于这个问题,我在第24篇中有详细描述