Reputation: 10585
Perhaps it is just me, but I find certain aspects of swift... obtuse to say the least.
I don't use Interface Builder most of the time because I like using PureLayout
. So I was hoping to make a UIViewController
subclass, say PureViewController
, that had a handy init
without parameters:
class PureViewController : UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
}
}
But this is not okay, for XCode tells me I must also implement init(coder aDecoder: NSCoder)
. Okay, that's fine! That's why I made this class - so I don't have to do this again for subclasses.
class PureViewController : UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Ok, now here's what I don't get.
I define a subclass, SomePureViewController : PureViewController
, with an initializer init(viewModel:ICrackersViewModel)
...
class SomePureViewController : PureViewController {
init(viewModel:ICrackersViewModel) {
super.init()
}
}
But it STILL wants me to define the same stupid initializer till kingdom come!
class SomePureViewController : PureViewController {
init(viewModel:ICrackersViewModel) {
super.init()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now I understand the idea - there is no init(decoder)
in my subclass, even though it is defined in its parent class.
Maybe I've always dealt with this issue with UIViewController
and never noticed it before.
My questions are as follows:
Upvotes: 4
Views: 631
Reputation: 4610
The point is that one can initialize a possibly derived class just by knowing the base type.
Lets assume a base class
class Base {
let value: Int
required init(value: Int) {
self.value = value
}
}
and a function
func instantiateWith5(cls: Base.Type) -> Base {
return cls.init(value: 5)
}
then we can do
let object = instantiateWith5(Base.self)
Now if someone defines a derived class
class Derived: Base {
let otherValue: Int
init() {
otherValue = 1
super.init(value: 1)
}
required init(value: Int) {
fatalError("init(value:) has not been implemented")
}
}
We are at least able to call
let object2 = instantiateWith5(Derived.self)
violating LSP, but that's a problem of your code, not the language.
Swift has to guarantee that initializers leave your objects in a initialized state, even when they are derived from a base object, so I guess changing that would be a bad thing. If you like to define a UIViewController that is not deserializable and thereby violating LSP it's your decision - but don't expect the language to support you in this.
Upvotes: 2
Reputation: 114975
As the initialiser is marked with the required
keyword, all subclasses must implement that initialiser and they must also specify required
on their implementation so that their subclasses are also required to implement it.
Required Initializers
Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer
You must also write the required modifier before every subclass implementation of a required initializer, to indicate that the initializer requirement applies to further subclasses in the chain.”
This has been part of the Swift language since 1.0 and it is unlikely to change.
The issue is actually to do with the use of the required
keyword in the UIViewController class definition. In theory this could be changed, but again I think it is unlikely.
Upvotes: 1
Reputation: 1461
I think that this is swift issue and there is no way how to avoid this. We all hate this empty - fatal error initializer.
Upvotes: 1