I have the following class representing a button in my iOS 8 custom keyboard:
internal class KeyButton: UIButton {
required init(char: Character) {
super.init()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Since KeyButton is not initialised via storyboard the constructor (coder: NSCoder) would never be called.
The problem is that I am required to implement (coder: NSCoder) constructor, when I run the app I receive the exception plugin interrupted when instantiating KeyButton.
Why am I required to implement (coder: NSCoder) constructor although I instantiate everything programatically
It has nothing to do with the coder. UIButton's init() calls init(frame: CGRect), which you haven't implemented. Add the following, and you should be good to go...
override init(frame: CGRect ) {
super.init(frame: frame)
println("Button frame allocated")
}
Related
I have many custom View in my project ( UIView's subclass). And I need to override init method.
I just want to override init(frame: CGRect) method. And I don't want to write the same code init?(coder in many UIView subclasses again and again.
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
And I add an extension to UIView, then OK.
extension UIView{
convenience init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The problem occurs, when I custom UITableView class.
class Table: UITableView {
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
}
Xcode tips firstly,
'required' initializer 'init(coder:)' must be provided by subclass of 'UITableView'
class Table: UITableView {
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Xcode tips secondly,
Declaration 'init(coder:)' cannot override more than one superclass declaration
How to fix it?
You can inherit your CustomTableView class from a BaseTableView Class which is a subclass of UITableView. BaseTableView class will contain both initialiser method of UITableView. Eg:
class BaseTableView: UITableView {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
}
}
Then your custom classes are inherited from BaseTableView class with a convenience override method of init(frame:...
class Table1: BaseTableView {
convenience override init(frame: CGRect, style: UITableView.Style) {
self.init(frame: frame, style: style)
}
}
class Table2: BaseTableView {
convenience override init(frame: CGRect, style: UITableView.Style) {
self.init(frame: frame, style: style)
}
}
we use convenience override init to convey that this is a convenience init that has the same signature as the designated initializer in the superclass.
Because convenience init and required init conflicted. You can not have more than one implementation for an initializer.
This is my class of a UIView:
class overlap: UIView{
init() {
super.init(frame: UIScreen.main.bounds)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
}
It should just fill up the screen. When I add the view in Storyboard with constraints pinned to the edges of the screen, it crashes when I launch the app. The error comes up as stated in the code above.
Creating and adding the subclass programmatically works with this init function:
override init(frame: CGRect) {
super.init(frame: frame)
}
But I want it reusable through Storyboard, without adding code. What is wrong with my code, and is it even possible what I want?
Thanks!
it crashes when I launch the app
Because that is what your code told it to do.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
fatalError means "crash me".
This is my class of a UIView:
class overlap: UIView{
init() {
super.init(frame: UIScreen.main.bounds)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
}
It should just fill up the screen. When I add the view in Storyboard with constraints pinned to the edges of the screen, it crashes when I launch the app. The error comes up as stated in the code above.
Creating and adding the subclass programmatically works with this init function:
override init(frame: CGRect) {
super.init(frame: frame)
}
But I want it reusable through Storyboard, without adding code. What is wrong with my code, and is it even possible what I want?
Thanks!
it crashes when I launch the app
Because that is what your code told it to do.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
fatalError means "crash me".
I am creating a UIView subclass with the intention to force users to my required init method than the default one.
So for that, I have created a convenience method for this.
#available(*, unavailable, message: "init is unavailable.")
public override init(frame: CGRect) {
super.init(frame: frame)
}
required
convenience public init(withSomeParameters myParam:Type) {
self.init(frame: CGRect.zero)
//Doing something nice!
}
This works! However, when I try to init it's showing me two ways to initialize it. How to force the user to make use of custom init method?
You can make it private , so user must need to init Test class with withSomeParameters
class Test:UIView {
private override init(frame: CGRect) {
super.init(frame: frame)
}
convenience public init(withSomeParameters myParam:Type) {
self.init(frame: CGRect.zero)
//Doing something nice!
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Maybe you need to mark the coder initialiser as unavailable as well:
#available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Plus: remove the convenience from your initialiser, and call supers init(frame:)
public init(withSomeParameters myParam:Type) {
super.init(frame: .zero)
//Doing something nice!
}
As another example, here is some base UIView subclass I use in a lot of my projects that don't utilise storyboards:
class MXView: UIView {
init() {
super.init(frame: .zero)
}
// Storyboards are incompatible with truth and beauty.
#available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Subclass:
class CustomView: MXView {
init(someParameters params: Type) {
// Phase 1: store ivars.
super.init()
// Phase 2: Do something nice.
}
If you do it like that, users of CustomView will be forced to use init(someParamters:). init(frame:) is shadowed because init(someParameters:) is a non-convenience init.
The following code returns a couple of compiler errors after converting to swift3:
override init(frame: CGRect) { //Initializer does not override a designated initializer from its superclass
super.init(frame: frame) //Must call a designated initializer of the superclass 'MKAnnotationView'
}
How do I go about fixing this?
I am guessing (from the comment in your code) that you are trying to create a subclass of MKAnnotationView. If thats true, try this.
class myAnnot : MKAnnotationView{
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}