What is the difference between a required initializer and a designated initializer?

I created my own tableViewCell and then received an error message:

'required' initializer 'init (coder :)' must be provided by a subclass of 'UITableViewCell'

I looked through it, and obviously this is necessary for its implementation. But this led to my confusion regarding the necessary and designated initializers.

Apple Docs says:

Necessary initializers:

Write the required modifier before defining the initializer class to indicate that each subclass of the class must implement this initializer:

Designated initializers

The designated initializers are the primary initializers for the class. the designated initializer completely initializes all the properties introduced by this class and calls the corresponding initializer of the superclass to continue the process of initializing the superclass chain.

Are the following statements correct?

  • The required initializer is always the designated initializer.
  • Each designated initializer is optionally a required initializer.
  • A class can have only one initializer required, however, can it have multiple initializers assigned?

Having said that, I still do not fully understand their functional differences.

+7
initialization swift designated-initializer
source share
1 answer

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() { // Required from superclass/its protocol self.thing = 0 } required init(thing: Int) { // Required from new protocol self.thing = thing } } 

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) { // Required from superclass super.init(value: value) // Must call desginated initialiser of superclass } } let someBaseClassType: BaseClass.Type = SubClass.self let someBaseClassInstance = someBaseClassType.init(value: 1) 

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() // Must call designated initialiser of this class } init() { super.init(value: 0) // Must call designated initialiser of superclass } } 

(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.
+13
source share

All Articles