swift init()函数总结

一、很多情况下init方法并不是必须的

  • let常量可以用=号赋值好
  • var变量,可以先设置为nil(注意nil也是一个值)
  • 属性可以用闭包给它初始化一个值
  • 通过lazy机制
class Test{
    let a = ""
    var b : UIView!//X为nil,并不需要在初始化类时给它赋具体的值
    var c = {return "c"}
    lazy var d = {
        return "d"
    }()
}

二、默认初始化函数

如果在一个基类(没有父类)中,类中所有的属性都有默认值了,那么这个基类就会有一个默认的初始化函数 init()
如果在一个struct中,没有初始化函数,它会默认生成一个初始化函数,参数包括这个struct中的所有属性,包括let 和 var(如果let在定义的时候用=号给它默认值了,那么不会出现在初始化函数中)

例1:

struct test{
     var x:String!
     let y:Int32!
}

那么swift会为test struct生成一个默认的初始化函数

init(x:String!,y:Int32!)

例2

struct test2{
     var x:String!
     let y:Int32! = 32
}

那么swift会为test2 struct生成一个默认的初始化函数

init(x:String!)

三、designated 初始化函数 和 convenience 初始化函数

1.designated初始化函数

  • 默认没有任何修饰符的初始化函数就是designated初始化函数

例子:

class Test{
    let a = ""
    var b : UIView!
    var c = {return "c"}
    lazy var d = {
        return "d"
    }()

    //designated初始化函数
    init() {

    }
}
  • designated初始化方法需要保证所有非 Optional 的实例变量被赋值初始化

例子:

class Test{
    let a = ""
    var b : UIView!//X为nil,并不需要在初始化类时给它赋具体的值
    var c = {return "c"}
    lazy var d = {
        return "d"
    }()

    let e:Int

    //designated初始化函数
    init() {
        //由于e没有在定义的时候直接赋值,所以需要在desinged初始化方法中初始化
        self.e = 1
    }
}
  • 子类中会强制 (显式或者隐式地) 调用 super 版本的 designated 初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。
  • 如果子类中有父类中没有的属性,需要先在子类的designated初始化函数中先初始化这些属性,才能调用父designated初始化函数

例子:

class ClassA {
    let numA: Int
    init(num: Int) {
        numA = num
    }
}
class ClassB: ClassA {
    let numB: Int

    override init(num: Int) {
        numB = num + 1
        //先初始化numB再屌用父类init
        super.init(num: num)
    }
}

2.convenience初始化方法

  • 在 init 前加上 convenience 关键字的初始化方法
  • 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置
    例子:
class ClassA {
    let numA: Int

    init(num: Int) {
        numA = num
    }

    convenience init(bigNum: Bool) {
        self.init(num: bigNum ? 10000 : 1)
    }
}
  • convenience 的初始化方法是不能被子类重写或者是从子类中以 super 的方式被调用的(除非。。)

除非满足如下规则!:

  • 只要在子类中重写了父类 convenience 方法所需要的designated 初始化方法的话,我们在子类中就也可以使用父类的 convenience 初始化方法了

还要注意的是!:

如果你的类中没有定义任何designated初始化函数,那么类会继承它父类所有的designated初始化函数。
不然的话你不会继承任何一个父类的designated初始化函数(要么全继承,要么一个也不继承)
所以经常有人遇到问题,为什么我在子类中实现了一个初始化函数,从父类继承的其他初始化函数怎么不能用了。这就是因为一旦你开始实现自己的初始化函数那么你就不会从父类继承初始化函数

结合上面这条规则再扩展一下:

如果父类有一个required init函数(指子类必须要重写的designated初始化函数),那么要考虑如下情况:
1.子类如果没有定义任何的init函数。
那么它就会自动继承父类的所有init函数。
2.如果你自身定义了一个init函数
那么xcode会提示你,你必须要实现父类的required init,因为你不再从父类继承required init了

四、可以返回失败的init函数

有一些init函数是允许失败并且返回nil的,如果在init后面加一个?号或者一个!号的话

init?(arg1:Type1,...)  
init!(arg1:Type1,...)

那么说明它是一个允许返回失败的init函数
例子:

//image参数是一个Optional,如果应用中并没有交名称为"foo"的图片的话,那么必然会返回nil
let image = UIImage(named: "foo")     
//所以我们通常用if let语法来处理
if let image = UIImage(named: "foo") {
     //image was successfully created
}else{
     //do something else
}

参考资料:
《standford ios8》
《swift 文档》
Swifter