Table of Content

convenience

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.

大意是说,Convenience 关键字不是那么重要的,他的作用是定义一个用于补充 Designated init 方法的方法,使 init 方法可以更方便使用,所以一般情况是用不到的。

用法也很简单,看下面例子

import UIKit

class SomeClass: NSObject {

    var locationX: CGFloat
    var locationY: CGFloat

    init(x: CGFloat, y: CGFloat) {

        locationX = x
        locationY = y
    }

    convenience init(point: CGPoint) {

        self.init(x: point.x, y: point.y)
    }
}

class SomeSubclass: SomeClass {

}

let position = SomeSubclass(point: CGPointZero)

print(position.locationX)  

这里有一个有意思的现象,如果 SomeSubclass 里面有

override init(x: CGFloat, y: CGFloat) {
    super.init(x: x, y: y)
}

或者什么都不写,才可以使用

let position = SomeSubclass(point: CGPointZero)

@onevcat 所撰写的 DESIGNATED,CONVENIENCE 和 REQUIRED 里面写道

子类中也强制 (显式或者隐式地) 调用 super 版本的 designated 初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

那么问题来了,designated 初始化是什么,designated 我也翻译不好,designated initializer 就是指自己的 init 方法,为什么一定是自己的 init 方法呢,因为 super 的 init 方法需要加上 override 关键字。

Convenience 是必须调用 designated initializer,如果试图在 convenience 里面写成

locationX = point.x
locationY = point.y

会报错 use of 'self' in delegating initializer before self.init is calledself.init isn't called on all paths in delegating initializer

借用苹果文档一张图就是这样一个关系

required

如果第一个方法这样改写

required init(x: CGFloat, y: CGFloat) {

    locationX = x
    locationY = y
}

SomeSubclass 中如果自己有一个 init() 方法,编译器就会报错,让 insert required init(x: CGFloat, y: CGFloat) 这个方法。

当然了,如果 SomeSubclass 里面没有 init() 方法,designated initializer 依旧是会被隐式调用的。

所以,如果父类中有 convenience 方法想在子类中使用,或者父类的 init() 方法想在子类中也能用,就最好在 init() 加上 required 关键字。