Why child class inherit convenience initializer when overriding all designated initializer? - swift

class Parent {
var a : Int
init(a : Int) {
self.a =a
}
convenience init() {
self.init(a : 10)
}
}
class Child : Parent {
var b : Int
override init(a : Int){
b = 10
super.init(a : a)
}
}
var child = Child() // i know that convenience initializer is inherited, but why??
child.a // 10
child.b // 10
i know that convenience initializer is inherited, but why??
Just I override all designated initializer? so why is it need?

This is the rule as described in The Swift Programming Language:
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.
Inheriting convenience initializers is not needed if clients of the subclass don’t want to use them (just like inheriting methods and properties is not needed if clients of subclasses don’t use them), but it is the natural thing to do in my opinion.
Inheriting all of the superclass’s API is the default for subclasses, so convenience initializers should be inherited as well if possible. Since convenience initializers are required to call a sibling designated initializer, the compiler can be sure that all properties will be properly initialized only if all designated initializers are overridden in the subclass.

Related

Overriding superclass initializer in Swift

I've found numerous examples for using the Singleton pattern in Swift 3. I'm trying to use this method:
class Records: RailsData {
static let shared = Records()
private init() {}
...
}
When I do, I get the compiler error:
Overriding declaration requires an 'override' keyword
When I add the override keyword, it compiles and everything seems to work. Is the override needed because I'm subclassing RailsData? RailData is an abstract class in that it is not instantiated directly. I also didn't make it a singleton.
I'm trying to make sure I don't get bit later by using the override modifier...
You are not doing anything wrong ;) The override modifier is required because your RailsData superclass declares a designated initializer with the exact same signature:
class RailsData {
init() {...}
...
}
as such, the override modified is made necessary in your subclass. The same thing applies to inherited methods as well. From the The Swift Programming Language book:
When you write a subclass initializer that matches a superclass designated initializer, you are effectively providing an override of that designated initializer. Therefore, you must write the override modifier before the subclass’s initializer definition. This is true even if you are overriding an automatically provided default initializer.
As with an overridden property, method or subscript, the presence of the override modifier prompts Swift to check that the superclass has a matching designated initializer to be overridden, and validates that the parameters for your overriding initializer have been specified as intended.
Rest assured, you won't be bitten by this later on ;)
Motivating example. To see this initializer overriding in action, try this example:
class SuperClass {
init(x: Int) {
print("3. SuperClass.init(x: \(x))")
}
convenience init() {
print("1. SuperClass.init()")
self.init(x: 123) // Will be overridden by subclass.
}
}
class SubClass: SuperClass {
override init(x: Int) {
print("2. SubClass.init(x: \(x))")
super.init(x: x)
print("4. SubClass.init(x: \(x))")
}
}
// Calls inherited convenience initializer.
let sub = SubClass()
outputs:
SuperClass.init()
SubClass.init(x: 123)
SuperClass.init(x: 123)
SubClass.init(x: 123)
Abstract classes. By the way, there is no direct, linguistic support for abstract classes in Swift — nor in Objective-C — but at least Cupertino is thinking about it ;) Currently, such a concept is merely a soft convention used by frameworks authors, etc.
To add to #Paulo Matteo's comprehensive answer, this is most likely the fix you need:
override private init() {
super.init()
}

Swift Initialization Rule Confusion

Rule 1
If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.
Confusion: I provided one designated initializer in sub class. Its means no super class designated initializer will comes down to subclass. But I still needs to write override keyword to provide implementation of any super class designated initializer in sub class(which means super class designated init comes down to sub class). Rule 1 says if I provided subclass designated initializer then super class designated won't comes down. (Override only makes sense if we did not provided any designated init for sub class.)
class Food{
var name : String
init(foodName :String) {
self.name = foodName
}
}
class RecipieIngredient : Food{
var quantity : Int
init(fName :String, quantity :Int) {
self.quantity = quantity
super.init(foodName: fName)
}
override convenience init (foodName :String){
self.init(fName: foodName, quantity: 1)
}
}
It's because init() is not a protected method. So, if you define an init() method in the subclass, the compiler doesn't know whether you mean the init() method of the superclass, or the subclass. 'override' clears this up.

When override function with default value parameter, how to keep the default value same as superclass?

For example, this is a superclass:
class A {
public init(a: String = "aaaa") {
// this class is in a framework, and the subclass use that framework.
......
}
}
Is there a way to write a subclass and override the init with the same default value of parameter a?
The superclass is inside a framework. A project uses this framework, and want to override a function with default parameter value, but it seems there is no way to get the superclass default parameter value in the override function. I can write another function in the subclass, like check if a parameter is nil, then call the superclass with its default value, otherwise, pass the subclass parameter value to the superclass. But I want to find a way to write the exact same function name, that means to override the superclass function.
(This answer is up to date with Swift 3)
Placing the default parameter value in a convenience initializer, overriding the designated initializer onto which this convenience initializer points
You can let the public superclass initializer with a default argument be a convenience initializer, one that will be used as initializer "interface" for the superclass as well as the subclass. This convenience initializer in turn simply calls a fileprivate designated initializer which is the one you override in your subclass. E.g.
public class A {
let a: String
/* public initializer */
public convenience init(a: String = "aaaa") {
self.init(b: a)
}
/* "back-end" fileprivate initializer: implement initializer
logic here, and override this initializer in subclasses */
fileprivate init(b: String) {
self.a = b
print("super:", b)
}
}
public class B: A {
let b: String
override fileprivate init(b: String) {
self.b = "sub_" + b
print("sub:", b)
super.init(b: b)
}
}
/* The following initializations all call the convenience initializer defined in A */
let a = A() // prints> super: aaaa
let b = B() // prints> sub: aaaa, super: aaaa
let c = B(a: "foo") // prints> sub: foo, super: foo
print(a.a) // aaaa
print(b.a) // aaaa
print(b.b) // sub_aaaa
print(c.a) // foo
print(c.b) // sub_foo
In this simple example the subclass overrides all designated initializers of its superclass (here: one designated initializer), which is why also all the convenience initializers of its superclass (here: one) are available (inherited) by the subclass, as described by Rule 2 in the Language Guide - Initialization - Class Inheritance and Initialization - Automatic Initializer Inheritance.
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.

Call parent constructor when init a subclass in Swift

I've some classes which inherits from a base class. Usually with c++ classes I used to rewrite constructor in children and then call the parent one.
Is there a way in Swift to call parent constructor when init a subclass without rewriting it?
internal class A {
init(aBool: Bool? = false) {
...
}
}
class B: A {
init(aString: String) {
...
}
}
Having these two classes as example, I'd like to init B using the A constructor:
let obj = A(true)
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) { ... }
}
If you make B's init a convenience init it will not mask the original init and you will be able to do this...
class A {
var b: Bool? = nil
init(aBool: Bool? = false) {
self.b = aBool
}
}
class B: A {
var s: String? = nil
convenience init(aString: String) {
self.init(aBool: false)
self.s = aString
}
}
let obj1 = A(aBool: true) // obj1 is now an A, obviously.
let obj2 = B(aBool: true) // obj2 is now a B
You'll have to be careful to default or otherwise set all properties, though...
Alternatively, you can override the original init in B, and simply call super.init.

What are convenience required initializers in Swift?

I saw in this answer that the user specifies a convenience required init(). What exactly does this mean?
I understand that the required keyword is used for overriding a superclass's designated initializer, but what does the convenience required declarative do?
A convenience required initializer is an initializer that is enforced onto all subclasses but is not the designated initializer. This means that said initializer will eventually call a designated initializer in its initialization chain.
Designated Initialisers
A designated initialiser is the canonical initializer for a class and the one which all required and convenience initialisers should call. The Docs say:
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 Initialisers
A convenience initialiser is an initializer that sets up certain configuration information on a class...conveniently. Documentation:
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.
You do not have to provide convenience initializers if your class does
not require them. Create convenience initializers whenever a shortcut
to a common initialization pattern will save time or make
initialization of the class clearer in intent
Required Initialisers
Required initializers can be thought of as a binding contract between a parents interface and subsequent subclasses. Its your means of enforcing that all your children are aware of and implement a certain set of initialisers.
Write the required modifier before the definition of a class
initializer to indicate that every subclass of the class must
implement that initializer:
Declaring required initialiser of class as convenience lets subclasses easily inherit it and thus ommit its implementation
protocol P {
var some: Int! {get}
init(some: Int)
}
class C: P {
private(set) var some: Int!
convenience required init(some: Int) {
self.init()
self.some = some
}
}
class D: C {
// no need in required init(some: Int)...
}
A class initializer can be marked with required to indicate that every subclass of the class must implement that initializer.
As a subclass, you can use a designated initializer or a convenience initializer to satisfy this requirement.