当没有超类 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:),但从语义上看这似乎很奇怪。我有两个问题:

  1. 为什么我可以在视图控制器中调用 UIButton(),但不能在 UIButton 的子类中调用 super.init()
  2. 处理这种情况的最佳方法是什么,更一般地说,当 none 超类的初始值设定项看起来合适时我应该怎么做?

您在调用 super.init() 时遇到的问题是因为该初始化器实际上是一个 convenience 初始化器,而 sub类 必须调用一个指定的初始化器。大多数 UIKit/AppKit 类 都有一个接受 NSRect 的指定初始化器和一个不带参数的 convenience 初始化器,只是简单地链接到带有 .zero 的指定初始化器NSRect。当 Paulw11 建议用 .zero.

显式调用它时,他的评论暗示了这一点