I'm trying to create a simple Swift subclass of UIBarButtonItem:
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")
}
}
but when I try to instantiate this:
let countButton = LabelBarButtonItem(text: "0 items")
the code compiles correctly but fails at runtime with:
fatal error: use of unimplemented initializer 'init()' for class 'TestProject.LabelBarButtonItem'
I can't understand why this happens in this case, or what principle causes this problem in general. The init(text)
initializer should delegate directly to init(customView)
in the superclass. Why is init()
called at all? It shouldn't be involved.
Can anyone explain what's happening? Similar problems have popped up when I've tried to subclass other UIKit classes
The problem is that
init(customView:)
callsinit()
.And since you have a required initializer, you no longer inherit
init()
. Thus, you have to implement it, even if just to callsuper.init()
.You then face the (mild) annoyance of having to initialize all your properties in
init()
as well as ininit(text:)
. However, in your particular case, there was no need to do that in an initializer in the first place. I'd write your class like this:In your comment, you ask:
Correct. That's why I have marked the
init()
override asprivate
. Note that this works only if this class is off in a file by itself.Another possibility is to mark all your initializers (including
init(coder:)
) asconvenience
. Now you inheritinit()
and the whole problem goes away. However, this introduces another set of issues and is left as an exercise for the reader.Just to clarify, I regard this entire situation as a bug in Swift. It didn't behave like this, IIRC, until quite a recent revision (Xcode 6.1?). You are being hemmed in by the fact that
super.init(customView:)
calls yourinit()
. You could argue that that's wrong; you have a good use case for a bug report. Also the crash at runtime seems like wrong behavior; if this was going to happen, why didn't the compiler stop us? Perhaps someone else can justify what Swift does in this situation. I'm just trying to explain it.EDIT This answer is from 2014 and was intended to work around a bug that existed at that time. In modern iOS versions the bug is gone, and you can either say this:
or you can say this:
Neither of those was possible at the moment in time when the question was originally asked.