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.
Related
I am trying to create a new instance of a codable class, but I am not sure how to:
var x = Articles();
gives me the following error:
Missing argument for parameter 'from' in call
class Articles: Codable {
let value: [Article]?
}
I don't understand since this is a parameterless class. I have no idea what the from parameter is all about.
I don't understand since this is a parameterless class. I have no idea
what the from parameter is all about.
I get no error when I run the following:
class Articles: Codable {
let value: [Articles]?
init() {
value = nil
print("in init()")
}
}
var x = Articles()
output:
in init()
And without init():
class Articles: Codable {
let value: [Articles]?
// init() {
// value = nil
// print("in init()")
// }
}
var x = Articles() //Missing argument for parameter 'from' in call
First, read this:
Automatic Initializer Inheritance
As mentioned above, subclasses 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.
If you look at the docs, Codable is a typealias for the Decodable protocol (a protocol is like an interface in java). Protocols specify functions that a class must implement if they adopt the protocol. Your Articles class adopts the Decodable protocol. However, the docs for Decodable say,
init(from: Decoder)
Creates a new instance by decoding from the given decoder. Required.
Default implementation provided.
Protocols can actually implement functions by using extensions, which are then inherited by the class adopting the protocol.
As a result, the only designated initializer for your class is the one defined in the Decodable protocol, which takes one argument--which you inherit according to Rule 1. On the other hand, when you explicitly define another designated initializer in your class that takes no arguments, then you will call that initializer when you provide no arguments.
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()
}
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.
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.