Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a swift subclass *always* have to call super.init()

If I have a swift subclass that:

  1. doesn't need to access self
  2. doesn't need to access any properties on self

Do I still have to call super.init() in the subclass's init() method?

*Note: This is a different question than the one asked and answered here on SO because of the specifics listed in 1 and 2 above.

like image 960
bearMountain Avatar asked Aug 12 '14 06:08

bearMountain


People also ask

Do you have to call super init Swift?

This is called class inheritance or subclassing, the class you inherit from is called the “parent” or “super” class, and the new class is called the “child” class. For safety reasons, Swift always makes you call super. init() from child classes – just in case the parent class does some important work when it's created.

What is required init in Swift?

Swift init() Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.

What must a convenience initializer call?

The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.


Video Answer


2 Answers

No, you don't have to.

Assume you have the following classes.

class a {     let name: String      init() {         name = "james"     } }  class b: a {     let title: String      override init() {         title = "supervisor"     } } 

If you instantiate a variable with

let myVar = b()

Then,

  • override init() in b will be called
  • then the init() in a will be called

Even though you didn't explicitly call super.init().


This has been confirmed by Chris Laettner on the swift-user's email list. It kicks in when your super class has a single designated initializer with a zero-argument init. This is why you don’t have to call super.init() when deriving from NSObject.

*Thanks to Wingzero's comment below

like image 195
bearMountain Avatar answered Nov 10 '22 03:11

bearMountain


From the docs:

Designated initializers must call a designated initializer from their immediate superclass.

Also, regarding automatic initializer inheritance:

Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:

Rule 1 If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.

Rule 2 If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.

These rules apply even if your subclass adds further convenience initializers.

So the answer to your question is as follows:

Your subclass will always call a designated initializer of your superclass. If you don't write an initializer and the compiler doesn't complain, then it has used automatic initializer inheritance. And if you do write an initializer but it doesn't explicitly call a relevant upstream (or sidestream) initializer, it will be done for you automatically at the end of your initializer.

Furthermore, the way chained initializers work is in a 2-phase process. In the first phase, it starts from the subclasses towards superclasses, assigning default values to any parameters. In the second phase, the process is run backwards, starting with superclasses and ending with your subclass, where the customization of parameters is done and overridden.

This means that you must absolutely first in each init() set your variables, and then you're free to call (or not) the super.init() and run custom code. So as you asked above, if you want the super's init to run at the beginning, consider the 'beginning' to be just after your creating your variables:

class a {     var name: String      init() {         name = "james"         println("a")     } }  class b: a {     let title: String      override init() {         title = "supervisor"         super.init()         self.name = "john"         println("b")     } }  let x = b() 

This will print a, then b.

like image 31
Rikkles Avatar answered Nov 10 '22 03:11

Rikkles