当没有超类 init 适合时如何初始化子类
How to initialize a subclass when no superclass init fits
我知道这是一个愚蠢的例子,但它是我能想到的能说明我的问题的最小例子。
假设我有一个 Swift 5 项目,里面有一些 UI 按钮。作为背景,这个项目不使用故事板,并且在可能的情况下我没有为子视图指定框架,因为所有内容都使用各种 .constraint()
方法定位。另外,假设我的所有按钮都以以下两种方式之一声明:
let yellowButton = UIButton()
yellowButton.setTitleColor(.yellow, for: .normal)
let blueButton = UIButton()
blueButton.setTitleColor(.blue, for: .normal)
我决定通过创建 UIButton
的子类来压缩它,我可以将其构造为 let yellowButton = MyButton(isYellow: true)
,因为只有两种颜色。我试着写这样的东西:
import UIKit
class MyButton: UIButton {
private var isYellow: Bool
required init?(coder: NSCoder) {
fatalError("Not using storyboards")
}
init(isYellow: Bool) {
self.isYellow = isYellow
super.init() // <-- Compile error here
}
// ... code to handle color automatically ...
}
但是,它不让我调用super.init()
。它给了我 super.init(coder:)
、super.init(frame:)
、super.init(type:)
、super.init(frame:primaryAction:)
和 super.init(type:primaryAction:)
的选项。 None 其中看起来特别像我想要的。由于我使用约束来定位它,我想我可以用任意常量 CGRect 调用 init(frame:)
,但从语义上看这似乎很奇怪。我有两个问题:
- 为什么我可以在视图控制器中调用
UIButton()
,但不能在 UIButton 的子类中调用 super.init()
?
- 处理这种情况的最佳方法是什么,更一般地说,当 none 超类的初始值设定项看起来合适时我应该怎么做?
您在调用 super.init()
时遇到的问题是因为该初始化器实际上是一个 convenience
初始化器,而 sub类 必须调用一个指定的初始化器。大多数 UIKit/AppKit 类 都有一个接受 NSRect
的指定初始化器和一个不带参数的 convenience
初始化器,只是简单地链接到带有 .zero
的指定初始化器NSRect
。当 Paulw11 建议用 .zero
.
显式调用它时,他的评论暗示了这一点
我知道这是一个愚蠢的例子,但它是我能想到的能说明我的问题的最小例子。
假设我有一个 Swift 5 项目,里面有一些 UI 按钮。作为背景,这个项目不使用故事板,并且在可能的情况下我没有为子视图指定框架,因为所有内容都使用各种 .constraint()
方法定位。另外,假设我的所有按钮都以以下两种方式之一声明:
let yellowButton = UIButton()
yellowButton.setTitleColor(.yellow, for: .normal)
let blueButton = UIButton()
blueButton.setTitleColor(.blue, for: .normal)
我决定通过创建 UIButton
的子类来压缩它,我可以将其构造为 let yellowButton = MyButton(isYellow: true)
,因为只有两种颜色。我试着写这样的东西:
import UIKit
class MyButton: UIButton {
private var isYellow: Bool
required init?(coder: NSCoder) {
fatalError("Not using storyboards")
}
init(isYellow: Bool) {
self.isYellow = isYellow
super.init() // <-- Compile error here
}
// ... code to handle color automatically ...
}
但是,它不让我调用super.init()
。它给了我 super.init(coder:)
、super.init(frame:)
、super.init(type:)
、super.init(frame:primaryAction:)
和 super.init(type:primaryAction:)
的选项。 None 其中看起来特别像我想要的。由于我使用约束来定位它,我想我可以用任意常量 CGRect 调用 init(frame:)
,但从语义上看这似乎很奇怪。我有两个问题:
- 为什么我可以在视图控制器中调用
UIButton()
,但不能在 UIButton 的子类中调用super.init()
? - 处理这种情况的最佳方法是什么,更一般地说,当 none 超类的初始值设定项看起来合适时我应该怎么做?
您在调用 super.init()
时遇到的问题是因为该初始化器实际上是一个 convenience
初始化器,而 sub类 必须调用一个指定的初始化器。大多数 UIKit/AppKit 类 都有一个接受 NSRect
的指定初始化器和一个不带参数的 convenience
初始化器,只是简单地链接到带有 .zero
的指定初始化器NSRect
。当 Paulw11 建议用 .zero
.