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.
Related
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.
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()
}
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.
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.
Here is my code:
public class A<T : Any> {
public init(n : Int) {
print("A")
}
}
public class B : A<Int> {
}
public class C : B {
}
let x = C(n: 123)
This fails compilation and yells such error:
repl.swift:9:9: error: 'C' cannot be constructed because it has no accessible initializers
The following code can be compiled.
public class A {
public init(n : Int) {
print("A")
}
}
public class B : A {
}
public class C : B {
}
let x = C(n: 123)
Shouldn't requirement types specified generic types' initializers be inherited?
========Additional Below=======
“Superclass initializers are inherited in certain circumstances, but only when it is safe and appropriate to do so. For more information, see Automatic Initializer Inheritance below.”
---Apple Inc. “The Swift Programming Language (Swift 2)” iBooks.
And this
“However, superclass initializers are automatically inherited if certain conditions are met.”
“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.”
When looking into the first code, subclass B doesn't define any designated initializers,it should automatically inherits all of its superclass designated initializers, those from A<Int>.But actually it didn't which seems wired to me.
How about that ?? I try to use override code and super.init, it 's not error. I think that you don't have to init function with generic types.
try to put override init function in class B and class C.
Look like this,
public override init(n:Int) {
super.init(n: n)
}
Your failing code now compiles (since Swift 3). There is no mention of this change in the Swift 3 Language changes, so I can only assume that this was a bug.