“两阶段初始化”(Two-Phase Initialization)是 Swift 中确保类的所有属性在使用前被完全初始化的一种机制。它适用于所有类(class)类型,尤其是存在继承关系时非常重要。
什么需要两阶段初始化?
因为 Swift 允许类有继承关系,子类可能在初始化时要依赖父类的内容,必须确保:
1、所有属性都有值;
2、初始化顺序安全;
3、父类部分初始化完成之前,子类不能访问自己或父类的方法/属性。
两阶段初始化过程
第一阶段:初始化自身所有属性
子类先为自己的非可选属性设定值。
然后调用 super.init(…),让父类也完成初始化。
在第一阶段完成之前,不能使用 self,包括访问属性、调用方法等。
例如:
class ScreenshotOverlayView: NSView {
var selectionLayer: CAShapeLayer
override init(frame frameRect: NSRect) {
super.init(frame: frameRect) // 先初始化父类属性,会提示:Property 'self.selectionLayer' not initialized at super.init call
selectionLayer = CAShapeLayer()
}
}
在NSView子类代码中,重写构造器,因为先初始化父类属性,就会报错:
Property 'self.selectionLayer' not initialized at super.init call
这是Swift的初始化规则,要求必须在super.init()之前,完成子类中非可选的属性初始化。
因为selectionLayer变量是非可选类型:
var selectionLayer: CAShapeLayer // 非可选,没有默认值
因此,违反了Swift的两阶段初始化规则 — 所有非可选属性必须在调用 super.init 之前初始化完毕。
第二阶段:使用 self(属性、方法都可以使用)
父类初始化完成,回到子类构造器。
此时可以自由访问 self、使用方法、设置属性等。
class ScreenshotOverlayView: NSView {
var selectionLayer: CAShapeLayer
override init(frame frameRect: NSRect) {
selectionLayer = CAShapeLayer() // 完成子类非可选类型初始化
super.init(frame: frameRect) // 完成父类初始化
selectionLayer.fillColor = .white // 使用 self 修改属性和方法
}
}
使用示例
1、两阶段初始化
class Animal {
var name: String
init(name: String) {
self.name = name // 初始化自己的属性
print("Animal init")
}
}
class Dog: Animal {
var breed: String
init(name: String, breed: String) {
self.breed = breed // 初始化子类自己的属性(第一阶段)
super.init(name: name) // 调用父类 init(仍然在第一阶段)
print("Dog initialized with name: \(self.name) and breed: \(self.breed)") // 现在可以使用 self(第二阶段)
}
}
总结
Swift 的初始化顺序非常严格,尤其是涉及到类继承(如 NSView)时:
1、所有非可选的属性都必须在调用 super.init() 之前初始化,或者在声明时就提供默认值;
2、在super.init()之前,不可以调用方法或者访问为初始化的属性,也不可以传递self到其他地方。
override init(frame frameRect: NSRect) {
complete() // 在使用super.init之前不能调用方法,否则报错:'self' used in method call 'complete' before 'super.init' call
super.init(frame: frameRect)
}
3、推荐使用属性默认值 + 简洁构造器,减少出错空间。
相关文章
1、Swift完整初始化覆盖链:https://fangjunyu.com/2025/07/31/swift-%e5%ae%8c%e6%95%b4%e5%88%9d%e5%a7%8b%e5%8c%96%e8%a6%86%e7%9b%96%e9%93%be/
2、SwifUI @State初始化报错原因与修复方法:https://fangjunyu.com/2024/12/03/swifui-state%e5%88%9d%e5%a7%8b%e5%8c%96%e6%8a%a5%e9%94%99%e5%8e%9f%e5%9b%a0%e4%b8%8e%e4%bf%ae%e5%a4%8d%e6%96%b9%e6%b3%95/
3、@State的初始化机制和Swift的编译器规则:https://fangjunyu.com/2024/11/25/state%e7%9a%84%e5%88%9d%e5%a7%8b%e5%8c%96%e6%9c%ba%e5%88%b6%e5%92%8cswift%e7%9a%84%e7%bc%96%e8%af%91%e5%99%a8%e8%a7%84%e5%88%99/
4、Swift私有化初始化方法:https://fangjunyu.com/2024/10/19/swift%e7%a7%81%e6%9c%89%e5%8c%96%e5%88%9d%e5%a7%8b%e5%8c%96%e6%96%b9%e6%b3%95/