objective-c - 是什么导致 UIBarButtonItem 出现此初始化程序继承问题?

标签 objective-c swift initializer designated-initializer

我正在尝试创建一个 UIBarButtonItem 的简单 Swift 子类:

class LabelBarButtonItem: UIBarButtonItem {
  let label: UILabel

  init(text: String) {
    self.label = UILabel(frame: CGRectZero)
    self.label.tintColor = UIColor.grayColor()
    super.init(customView: self.label)
    self.label.text = text
  }

  required init(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
}

但是当我尝试实例化它时:

let countButton = LabelBarButtonItem(text: "0 items")

代码编译正确但在运行时失败:

fatal error: use of unimplemented initializer 'init()' for class 'TestProject.LabelBarButtonItem'

我无法理解为什么在这种情况下会发生这种情况,或者一般来说是什么原理导致了这个问题。 init(text) 初始化程序应直接委托(delegate)给父类(super class)中的 init(customView)。为什么要调用 init()?不应该涉及。

谁能解释一下发生了什么?当我尝试子类化其他 UIKit 类时出现了类似的问题

最佳答案

问题是 init(customView:) 调用了 init()

并且因为你有一个必需的初始化器,你不再继承init()。因此,您必须实现它,即使只是调用 super.init()

然后,您将面对必须在 init()init(text:) 中初始化所有属性的(轻微的)烦恼。但是,在您的特定情况下,首先不需要在初始化程序中执行此操作。我会这样写你的课:

class LabelBarButtonItem: UIBarButtonItem {
    let label = UILabel(frame: CGRectZero)
    init(text: String) {
        super.init(customView: self.label)
        self.label.text = text
        self.label.tintColor = UIColor.grayColor()
    }
    private override init() {
        super.init()
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

在你的评论中,你问:

But now if I override init(), clients of my class can create an invalid instance of LabelBarButtonItem by just calling LabelBarButtonItem()

正确。这就是为什么我将 init() 覆盖标记为 private 的原因。请注意,只有当此类本身在文件中关闭时,这才有效。

另一种可能性是将所有初始化器(包括init(coder:))标记为convenience。现在你继承了 init(),整个问题就迎刃而解了。但是,这会引入另一组问题,留给读者作为练习。

澄清一下,我将整个情况视为 Swift 中的一个错误。直到最近的修订(Xcode 6.1?),它才表现得像这样,IIRC。您被 super.init(customView:) 调用您的 init() 这一事实所困扰。你可能会争辩说那是错误的;您有一个很好的错误报告用例。运行时的崩溃似乎也是错误的行为;如果这会发生,为什么编译器不阻止我们呢?也许其他人可以证明 Swift 在这种情况下所做的事情。我只是想解释一下。

编辑 这个答案来自 2014 年,旨在解决当时存在的错误。在现代 iOS 版本中,这个错误已经消失,你可以这样说:

class LabelBarButtonItem: UIBarButtonItem {
    init(text: String) {
        let label = UILabel(frame: .zero)
        label.text = text
        label.sizeToFit()
        super.init()
        self.customView = label
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

或者你可以这样说:

class LabelBarButtonItem: UIBarButtonItem {
    convenience init(text: String) {
        let label = UILabel(frame: .zero)
        label.text = text
        label.sizeToFit()
        self.init(customView: label)
    }
}

在最初提出问题时,这些都不可能。

关于objective-c - 是什么导致 UIBarButtonItem 出现此初始化程序继承问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27115622/

相关文章:

iOS UIBarButtons 不设置由 UIActionSheet iOS 6.1 启用

objective-c - iOS 5 与 iOS 6 中的自动旋转问题

iphone - 是否允许调用 [self release] 来控制对象的生命周期?

iphone - iOS XML 编写器类

swift - @EnvironmentObject 符合协议(protocol): Xcode not compiling

ios - 如何在 Swift 中访问 JSON 响应中的特定数据

C++编译错误:expected initializer before ‘<’ token

c++ - `const std::string& s = nullptr` 作为可选参数如何工作

ios - 使用自定义 setter 和计算结构属性的两种方式转换

python - 具有三个参数的 Reduce 函数