摘要:Swift有着超级严格的初始化方法,不只强化了designated初始化方法的地位,全部不加修饰的init方法都须要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化。安全
咱们在深刻初始化方法以前,不妨先再想一想Swift中的初始化想要达到一种怎样的目的。app
其实就是安全。在Objective-C中,init方法是很是不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用之后,实例的各个变量都完成初始化,甚至若是在初始化里使用属性进行设置的话,还可能会形成各类问题。虽然Apple也明确说明了不该该在init中使用属性来访问,但这并非编译器强制的,所以仍是会有不少开发者犯这样的错误。ide
因此Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都须要在方法中保证全部非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,因此不管如何走何种路径,被初始化的对象老是能够完成完整的初始化的。oop
在上面的示例代码中,注意在init里咱们能够对let的实例常量进行赋值,这是初始化方法的重要特色。在Swift中let声明的值是不变量,没法被写入赋值,这对于构建线程安全的API十分有用。而由于Swift的init只可能被调用一次,所以在init中咱们能够为不变量进行赋值,而不会引发任何线程安全的问题。ui
与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是Swift初始化方法中的“二等公民”,只做为补充和提供使用上的方便。全部的convenience初始化方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。spa
只要在子类中实现重写了父类convenience方法所须要的init方法的话,咱们在子类中就也可使用父类的convenience初始化方法了。好比在上面的代码中,咱们在ClassB里实现了init(num: Int)的重写。这样,即便在ClassB中没有bigNum版本的convenience init(bigNum: Bool),咱们仍然仍是能够用这个方法来完成子类初始化:.net
所以进行一下总结,能够看到初始化方法永远遵循如下两个原则:线程
对于某些咱们但愿子类中必定实现的designated初始化方法,咱们能够经过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是能够保证依赖于某个designated初始化方法的convenience一直能够被使用。一个现成的例子就是上面的init(bigNum: Bool):若是咱们但愿这个初始化方法对于子类必定可用,那么应当将init(num: Int)声明为必须,这样咱们在子类中调用init(bigNum: Bool)时就始终可以找到一条彻底初始化的路径了:code
另外须要说明的是,其实不只仅是对designated初始化方法,对于convenience的初始化方法,咱们也能够加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会很是有帮助。对象