Mandatory initializers and designated initializers are not actually related, although the corresponding keywords required and convenience are used to indicate restrictions on subclasses.
Required Initializers
The required initializer ensures that you can initialize the type or any of its subtypes using this initializer. If you have an initializer in the protocol and you comply with this protocol, you should use required (if it is a class), because this protocol ensures that the initializer is present in this class and in any of its subclasses. When you use required in the class initializer, this means that all of its subclasses can also be initialized using this method. This means that you also need to add this initializer to any of its subclasses.
protocol TestProtocol { init() } class TestClass: TestProtocol { required init() { } }
The required keyword should be present here because any subclasses of TestClass must also provide init() (because they also match TestProtocol ).
Having the required initializer allows you to initialize the class without knowing that it is at compile time, which is useful for various reasons:
let classType: TestProtocol.Type = TestClass.self let object = classType.init()
If your class conforms to several protocols, each of which has a different initializer, for example, each of these initializers is also necessary:
protocol OtherProtocol { init(thing: Int) } class OtherClass: TestClass, OtherProtocol { let thing: Int required init() {
Note that adding super.init() not required in this special case, since Swift will automatically include the call if it does not accept any parameters.
In all of the above examples, initializers are indicated because they do not include the convenience keyword.
Even if you didn't have protocols, you can still use required by initializing a class type that is unknown at compile time:
class BaseClass { let value: Int required init(value: Int) { self.value = value } } class SubClass: BaseClass { required init(value: Int) {
Assigned Initializers
A designated initializer is one that is not a convenience initializer (i.e., convenience labeled). The designated initializer must make sure that all the properties of the class have a value until the initialization is complete (or the super initializer is called). Convenience initializers do not have this requirement because they themselves must name the designated initializer.
class OtherSubClass: BaseClass { convenience required init(value: Int) { self.init()
(This is a pretty far-fetched example.)
In my experience, convenient initializers are rarely useful, and I try to find that the problems they solve can be solved using optional arguments for the designated initializers. It is also necessary to take into account the fact that initializers cannot call convenient initializers on their superclass , so make sure that you do not have convenient initializers that provide functionality, initializers do not do this if you intend to subclass your class!
Structures and enumerations do not use the required or convenience keywords because these keywords are used to indicate initialization rules for subclasses that only support class es: The required keyword indicates that subclasses should provide this initializer and the convenience keyword indicates that subclasses do not can call this initializer. Despite the lack of keywords, they should still provide initializers defined in any protocols that they conform to, and you can write "convenient" initializers that call self.init , just without the convenience keyword.
To answer your statements:
- Mandatory initializers do not have to be specified.
- Assigned initializers are not required.
- Classes can have several required and assigned initializers.