Call Parent Constructor When Init a Subclass in Swift

Call parent constructor when init a subclass in Swift

The rules from Apple state that:

[S]ubclasses do not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you do not need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it is safe to do so.

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.

What does all that mean? If you make your subclass B's initializer a convenience initializer, then then B should inherit all of A's designated initializers.

class B: A {
convenience init(aString: String) { ... }
}

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

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

How to override Init() in the subclass in Swift 3

So you have two ways to handle your case:

1 Create an own initializer for your subclass, call the super initializer and after that initialize the weapon property like this

class Goblin: NonPlayerCharacter {
var weapon : Int = 0

init(health: Int, power: Int, weapon: Int) {
super.init(health: health, power: power)
self.weapon = weapon
}

override func attack() -> String {
return "attack from Goblin"
}
}

Then you are able to create a Goblin like this:

var goblin1 = Goblin(health: 30, power: 20, weapon: 50)

2 Create a convenience initializer for your subclass to be able to decide if you want to call only the initializer from the parent class (with setting health and power) or the convenience one (with setting health, power and weapon) like this:

class Goblin: NonPlayerCharacter {
var weapon : Int = 0

convenience init(health: Int, power: Int, weapon: Int) {
self.init(health: health, power: power)
self.weapon = weapon
}

override func attack() -> String {
return "attack from Goblin"
}
}

Then you are able to create a Goblin like this:

var goblin2 = Goblin(health: 30, power: 20, weapon: 50)

or like this:

var goblin3 = Goblin(health: 30, power: 20)

Further readings here and here

super init constructor in Swift

You can't assign to self in Swift. Just use

super.init()

You also don't return anything. Constructors are of type void (in C lingo).

Inherit from class with private initializer?

There are various ways to solve this issue:

  1. Declare the initializer as internal, that will give you module access and your subclass will be able to call it.

  2. Declare the classes in the same file, then private won't be an issue anymore (private enables access from the same file).

  3. Instead of abstract classes, you can make MapItem a protocol and ClusterItem and Cluster could inherit from GMSMarker directly. However, this solution may not be good depending on your exact needs.

Inheritance and constructors. Self used before super.init

Make init?(json (also) a designated initializer

init?(json: [String: Any]) {
guard let id = json["id"] as? String,
let link = json["link"] as? String else{
print("Failed Base Class Init!")
return nil
}
self.id = id
self.link = link
}

And override it in the subclass

override init?(json: [String: Any]) {
super.init(json: json)
...


Related Topics



Leave a reply



Submit