Swift的Designated和Convenience初始化器

前言

在Swift中,为了确保类的存储属性都能有一个初始值,提供了几种初始化的方法,接下来将讨论一下Desinated(指定)、Convenience(便捷)初始化器。

Designated(指定)初始化器

  • 之前使用过Objective-C的应该比较了解指定初始化器,很多类都提供了指定初始化器,如UIViewController的为:- (instancetype)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle,UIView的- (instancetype)initWithFrame:(CGRect)aRect,其作用是该类或者其子类在初始化的过程中都会调用指定初始化器。

  • 当在类中定义指定初始化器时,该初始化器会初始化该类的所有存储属性,且当该类是有父类时,必须调用父类的指定初始化器,注意顺序,先初始化该类自己定义的存储属性,再使用super来调用父类的指定初始化器,跌倒过来编译器会报错。

1
2
3
4
5
6
7
8
9
10
11
class RecipeIngredient: Food {
var quantity: Int
//指定初始化器
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name) //放在该类存储属性初始化之后
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
  • 每一个类都必须至少有一个指定初始化器。

Convenience(便捷)初始化器

  • 便捷初始化器需要带一个convenience修饰符,如下代码,在便捷初始化器的定义中,必须先调用其他的初始化器之后,再赋类的存储属性值

    1
    2
    3
    convenience init(parameters) {
    statements
    }
  • 便捷初始化器如果重载了父类的指定初始化器,则必须使用override修饰符。

  • 如果子类提供了其父类的所有(注意:必须是所有的)指定初始化器的实现,实现有两种,一种是子类的存储属性都提供了默认值,且没有定义指定初始化器,则会自动集成父类的指定初始化器;另一种是在子类中重新定义,子类中重新定义的方法可以是便捷初始化器,既子类中的便捷初始化器可以重载父类的指定初始化器。这样子类就会自动继承父类的便捷初始化器。

  • 在Extensions中只能添加便捷初始化器。

指定初始化器和便捷初始化器之间的关系

指定初始化器和便捷初始化器之间的3个法则:

  1. 指定初始化器必须调用其直接父类的指定初始化器。
  2. 便捷初始化器必须调用该类中其他的初始化器,其初始化器的类型不限。
  3. 在便捷初始化器的调用链中最后必须调用一个指定初始化器。

最后,直接上官方文档的图示就会对上面的3个规则有比较清晰的认识: