我正在尝试创建一个 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/