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()
inb
will be called- then the
init()
ina
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:
Declare the initializer as
internal
, that will give you module access and your subclass will be able to call it.Declare the classes in the same file, then
private
won't be an issue anymore (private
enables access from the same file).Instead of abstract classes, you can make
MapItem
aprotocol
andClusterItem
andCluster
could inherit fromGMSMarker
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
Swift Access to Variable Length Array
How to Cast a Uint64 to an Int64
Possible to Pass an Enum Type Name as an Argument in Swift
Swiftui Label Text and Image Vertically Misaligned
Extension for Generic Type 'Unsafemutablepointer<Uint8>'
Swift Combine How to Skip an Event
Nsjsonserialization Not Working as Expected in a Playground
Swift - Force Synchronous Execution of Work and Subsequent UI Rendering
How to Create Uicollectionviewcell Programmatically
How to Get Multiple Lines of Stdin Swift Hackerrank
Why Swift Closure Not Capture Self
Swiftui: How to Make a Button Open a Url in Safari
Add Constraints to Generic Parameters in Extension
Alamofire Type 'Parameterencoding' Has No Member 'Url' Swift 3
Cannot Add Alamofire to Swift Project