Understanding init() when sub-classing in Swift - swift

How can I add a custom initializer when inheriting from a class that already has an initializer?
What I have is a Vehicle class which has an itializer who takes an argument name. What I want to do is inherit from this Vehicleclass, create another initializer for the new class but keep using the existing initializer.
Base Class (No problem here):
class Vehicle{
var make:String
init(make:String){
self.make = make
}
}
New Class (Doesn't work):
// Not sure how to structure this class
class Car:Vehicle {
var engine:Double
override init(){
super.init()
}
init(engine:Double){
self.engine = engine
}
}
This is what I would like to be able to do... re-use the existing initializer plus the new one.
let cobalt = Car(make:"Chevy" engine: 2.5)

Any designated initializer in a subclass must call a designated initializer from its immediate superclass:
Initializer Delegation for Class Types
To simplify the relationships between designated and convenience
initializers, Swift applies the following three rules for delegation
calls between initializers:
Rule 1 A designated initializer must call a designated initializer
from its immediate superclass
...
From the Swift Language Guide - Initialization.
Hence, you could construct your designated initializer of Car to take two arguments, make and engine, and use the latter to inititalize the member property engine of the subclass, thereafter call the designated initializer of the superclass using the supplied make parameter (supplied to subclass initializer) as argument to the superclass initializer.
class Car: Vehicle {
var engine: Double
init(make: String, engine:Double){
self.engine = engine
super.init(make: make)
}
}

Related

questions about super.init and ()

I am confused when you have a child class that inherit from a parent class.
First question is why use super.init? I understand override init so it can override the values that was previously set from the parent but I don't understand the use of super.init..
Second question is why does init have parameters?
EDIT: Also why sometimes, the parent class also have a init??
class car {
var speed = 5
var model: String?
var age: Int?
}
class bmw: car {
override init() {
super.init()
model = "cat"
}
}
In your example, there is no good reason for calling super. But in general any class may have properties to initialize and other initial tasks to perform, and the rule, which says that a designated initializer of a subclass must call a superclass designated initializer, guarantees that this will happen coherently both for the subclass and for the superclass.

Swift initializer for public class

When creating a public class, is it necessary to make the designated initializer public?
What's the difference between making it public vs not?
e.g.
public class A {
init() {}
}
or
public class A {
public init() {}
}
No
You do not need to make it public. In fact, you can make it private. The only thing special about a designated initializer (and your classes are allowed more than one) is that they are responsible for ensuring the object is fully initialized.
A convenience initializer (an initializer is either designated or convenience) (marked by the convenience keyword) does not have this responsibility. A convenience initializer delegates to a designated initializer first, and then after that returns, it is given the opportunity to overwrite some of the initial values. Importantly, the convenience initializer must always "delegate across". It must always call another initializer within the class.
By contrast, a designated initializer (any initializer not marked with the convenience keyword) must take responsibility for making sure every property in the class gets a valid initial value, then it must "delegate up" (call a super class initializer, if there is a super class), then it can overwrite values if it wants.
But nothing prevents you from create a class with nothing but private designated initializers (nothing at all).
Even when we are inheriting from a class with a required initializer, our subclass can simply implement that initializer as a convenience initializer.
class ParentClass {
let foo: Int
required init(foo: Int) {
self.foo = foo
}
}
class ChildClass: ParentClass {
let bar: Int
private init(foo: Int, bar: Int) {
self.bar = bar
super.init(foo: foo)
}
required convenience init(foo: Int) {
self.init(foo: foo, bar: foo)
}
}
The above is perfectly valid Swift.
ChildClass has a private designated initializer. It has inherited from a parent class with a required initializer, but it has implemented that initializer as a convenience initializer. (Moreover, in contrast to your conjecture in a comment here and a question else where, the required initializer doesn't actually have to be public necessarily... context matters, and perhaps I will expand on that in an answer to your other question.)
Moreover, in direct contrast to subjective_c's answer, you don't have to make parts of your Swift code public in order to use that code from Objective-C, and the passage from Apple he has quoted in his answer actually indicates that. You only need to mark public the things you want to be available outside of the framework in which your code has been implemented. You can put Objective-C & Swift code within the same application and the Objective-C code can see anything marked as public or internal.
You don't need to make it public unless you are making it available as a framework for usage in Objective-C as well.
See: https://developer.apple.com/swift/blog/?id=5
When mixing Objective-C and Swift, because the generated header for a
framework is part of the framework’s public Objective-C interface,
only declarations marked public appear in the generated header for a
Swift framework.

Unable to add a convenience initialiser to an SKShapeNode subclass

Trying to add a convenience init to an SKShapeNode subclass generates two compiler errors:
class Shape : SKShapeNode {
convenience init(diameter: CGFloat) {
self.init(circleOfRadius: diameter / 2) // error: Use of 'self' in delegating initializer before self.init is called
} // error: Self.init isn't called on all paths in delegating initializer
}
Yet, if you paste the following code into a playground, it compiles and executes as expected:
import CoreGraphics
import SpriteKit
class FakeShapeNode : SKNode {
convenience init(circleOfRadius radius: CGFloat) {
self.init()
}
}
class FakeShape : FakeShapeNode {
convenience init(diameter: CGFloat) {
self.init(circleOfRadius: diameter / 2)
}
}
let shape = FakeShape(diameter: 3)
The question is, what could be the relevant difference here between FakeShapeNode and SKShapeNode?
Edit
As suggested by #Knight0fDragon, below a reminder of the relevant initialisation rules may be helpful:
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.
You can't have a convenience init call the super's convenience init, it has to be a delegating initializer. Unfortunately there is a bug in playgrounds that will allow it to work, but in applications, you will receive the error you are seeing.
To understand how convenience inits work, please see https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html

Meaning of the convenience keyword in Swift

When I go back to look at some of Apple's Sprite Kit documentation I see a lot of occasions where a keyword called convenience comes up. For Example
convenience init(texture texture: SKTexture?, size size: CGSize)
What does it mean?
Convenience initialisers allow you to initialise a class without all the required parameters the designated initialiser needs.
For example, in a very basic example you may have a designated initialiser for a class that requires a String:
init someName(value: String) {
You could also create a convenience initialiser to go along side this that takes an int and converts it to a String and then calls the designated initialiser and passes it that String. This way if your class is initialised and passed an int instead or by mistake, it won't error and will handle it.
convenience init someName2(value: Int) {
let someString = String(value)
someName(value: someString)
}
Another use for them is that the designated initialiser may take multiple parameters. You could create a convenience initialiser to go along side this that takes only one of those parameters, creates the others and sets them to some default values and then calls the designated initialiser, passing them all in. This way you do not need to specify all required parameters of the designated initialiser since if you don't, your convenience initialiser will fill in missing ones with default values.
convenience init someName(value: String) {
someName(value: someString, value2: "DefaultValue")
}
init someName(value: String, value2: String) {
That is a convenience initializer.
From the docs:
Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.
An initializer that is not marked convenience is a designated initializer:
Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.
The docs I linked above are very detailed, because there is a lot to initialization. You'll need to read them to really understand what's going on. But to give an example, let's say you create a car class:
class Car {
let numberOfWheels: Int
init(numberOfWheels: Int) {
self.numberOfWheels = numberOfWheels
}
convenience init() {
self.init(numberOfWheels: 4)
}
}
The car class contains two initializers - a designated initializer and a convenience initializer.
The designated initializer is simply marked init. Inside a designated initializer, you are required to set all class properties so that the class is ready to go once initialization finishes. We set numberOfWheels inside our initializer.
The convenience initializer is marked convenience init. A convenience initializer may do whatever, but it must call one of the designated initializers before it finishes. In our example, it calls self.init(numberOfWheels: Int) and supplies a default number of wheels (4).
Convenience initializers are there exactly for their namesake: convenience. They allow you to set up initializers to classes that deal with common initialization cases. In our Car class, it is typical for a car to have four wheels, so our convenience initializer makes that common case easier.
To create a car, we can use either the designated initializer or the convenience initializer:
let carA = Car(numberOfWheels: 3) // makes a car with 3 wheels
let carB = Car() // makes a car with 4 wheels
There are a lot more rules around initialization, especially in class hierarchies where super.init and initializer inheritance must be considered as well. I cannot describe them all any better or more succinctly than the official documentation, so again, I suggest you check there.
Default init:
Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.
convenience init:
Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.
as per the Swift Documentation
Actually - Swift defines two kinds of initializers.
Designated initializers
Convenience initializers
Designated initializers are the primary initializers for a class. Every class should have at least one designated initializer.
init(parameters if any) {
}
Convenience initializers are secondary, supporting initializers for a class. Convenience initializers are written in the same style, but with the convenience modifier placed before the init keyword, separated by a space:
convenience init(parameters if any) {
}
Convenience init initializes the designated init method by calling self.init.
Example:
class HumanBeing {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: “not set”)
// Convenience init call the designated init method
}
}
let humanBeingObj1 = HumanBeing() // calls convenience init
let humanBeingObj2 = HumanBeing(name: “abhilash”) // calls designated init

Why use required Initializers in Swift classes?

I am trying to understand the use of the required keyword in Swift classes.
class SomeClass
{
required init() {
// initializer implementation goes here
}
}
required doesn't force me to implement the method in my child-class. If I want to override the required designated initializer of my parent class I need to write required and not override. I know how it works but can not understand why I should do this.
What is the benefit of required?
As far as I can tell, languages like C# don't have something like this and work just fine with override.
It's actually just a way of satisfying the compiler to assure it that if this class were to have any subclasses, they would inherit or implement this same initializer. There is doubt on this point, because of the rule that if a subclass has a designated initializer of its own, no initializers from the superclass are inherited. Thus it is possible for a superclass to have an initializer and the subclass not to have it. required overcomes that possibility.
One situation where the compiler needs to be satisfied in this way involves protocols, and works like this:
protocol Flier {
init()
}
class Bird: Flier {
init() {} // compile error
}
The problem is that if Bird had a subclass, that subclass would have to implement or inherit init, and you have not guaranteed that. Marking Bird's init as required does guarantee it.
Alternatively, you could mark Bird as final, thus guaranteeing the converse, namely that it will never have a subclass.
Another situation is where you have a factory method that can make a class or its subclass by calling the same initializer:
class Dog {
var name: String
init(name: String) {
self.name = name
}
}
class NoisyDog: Dog {
}
func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
let d = whattype.init(name: "Fido") // compile error
return d
}
dogMakerAndNamer is calling the init(name:) initializer on Dog or a Dog subclass. But how can the compiler be sure that a subclass will have an init(name:) initializer? The required designation calms the compiler's fears.
According to the documentation:
Write the required modifier before the definition of a class initializer to
indicate that every subclass of the class must implement that initializer
So yes, required does force all child classes to implement this constructor. However, this is not needed
if you can satisfy the requirement with an inherited initializer.
So if you have created more complex classes that cannot be fully initialized with a parent constructor, you must implement the require constructor.
Example from documentation (with some added stuff):
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
let thisNeedsToBeInitialized: String
required init() {
// subclass implementation of the required initializer goes here
self.thisNeedsToBeInitialized = "default value"
}
}
I want to draw an attention on another solution provided by Required, apart from Matt has given above.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
}
let instanceSubClass = subClass()
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Subclass Untitled"
As you can check in above example, I've declared required init() on superClass, init() initializer of superClass has inherited by default on subClass, So you able to create an instance of subClass let instanceSubClass = subClass().
But, suppose you want to to add one designated initializer on subClass to assign run time value to stored property neakName. Of course you can add it, but that will result to no initializers from the superClass will be inherited to subClass, So if you will create an instance of subClass you will create through its own designated initializer as below.
class superClass{
var name: String
init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
Here above, you won't be able to create an instance of subClass by just subClass(), But if you want that every subclasses of superClass must have their own init() initializer to create direct instance by subClass(). Just place required keyword before init() on superClass, it will force you to add init() initializer on subClass too - as below.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
} // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
SO, use required keyword before initializer on superclass, when you want all subclasses must have been implemented required initializer of superclass.
If you are trying to add you own initialiser in the sub class, then you have to follow certain things those were declared in super class. So it make sure that you will not forget to implement that required method. If you forget compiler will give you error // fatal error, we've not included the required init()
. Another reason is it creates a set of conditions that ever sub class should follow it the sub class is defining its own initialiser.