我认为指定初始化器和便利初始化器唯一的区别在于,前者必须调用超类 init(如果可用)。
那么我不明白为什么我无法在扩展中添加指定初始化器,但添加便利初始化器是可以的。
为什么从扩展中调用超类初始化器的初始化方法会被视为不好的做法?
我认为指定初始化器和便利初始化器唯一的区别在于,前者必须调用超类 init(如果可用)。
那么我不明白为什么我无法在扩展中添加指定初始化器,但添加便利初始化器是可以的。
为什么从扩展中调用超类初始化器的初始化方法会被视为不好的做法?
class ClassA {
private let propertyA: Int
init(propertyA: Int) {
self.propertyA = propertyA
}
}
class ClassB: ClassA {
private let propertyB: Int
init(propertyA: Int, propertyB: Int) {
self.propertyB = propertyB
super.init(propertyA: propertyA)
}
}
extension ClassB {
// If this was a designated initializer, you need to initialize propertyB before calling a superclass initializer.
// But propertyB is a private property that you can't access.
// If you don't have the source code of ClassB, you will not even know there is a property called propertyB.
// This is why we can't use extensions to add designated initializers.
init(propertyC: Int) {
...
}
}
我是从2023年写信的,所以可能有一些变化。所以,我们在扩展ClassB中可以访问private let propertyB。所以继续搜索更多,但对我来说问题仍然存在。
使用新信息编辑:
这是一个更好的例子。想象一下我们有
class Shape {
var backgroundColor: UIColor?
init(backgroundColor: UIColor?) {
self.backgroundColor = backgroundColor
}
}
class Rectangle: Shape {
var width: Int = 0
var height: Int = 0
}
let rectangle = Rectangle(backgroundColor: UIColor.green)
现在想象我们可以通过类似这样的扩展添加指定的初始化器:
extension Rectangle {
init(backgroundColor: UIColor?, width: Int, height: Int) {
self.width = width
self.height = height
super.init(backgroundColor: backgroundColor)
}
}
struct FirstStruct {
var prop1: Int
private var prop2: Int
}
extension FirstStruct {
init(prop: Int) {
self.prop1 = prop
self.prop2 = prop
}
}
ClassB
来访问私有的propertyB
。这并不会显著改变情况。你的第二个部分捕捉到了函数为什么永远不能被删除的要点(并且是为什么扩展只能添加方法而不能尝试更改方法的很好例子),尽管允许通过扩展在同一个文件中使用指定的初始化器并不会导致继承的初始化器被删除。在你的第三个示例中,初始化器并没有被删除。它从未存在过,因为prop2
是私有的。(移除扩展并尝试使用它。) - Rob Napierprop2
是私有的(在这种情况下不会自动生成)。结构体从不具有指定的初始化程序。“指定”的只用于继承。https://docs.swift.org/swift-book/documentation/the-swift-programming-language/initialization/#Designated-Initializers-and-Convenience-Initializers(此外,我强烈推荐整个页面) - Rob Napier