Swift Class Initialization Confusion
Answering your question directly: the initialization method is not necessary.
The variable randomizedSale
is static, so you don't need an instance to use it. It has nothing to do with the initialization.
Since all your variables and functions are static you don't need to write an init method. If create something like:
class A {
var x: Int
}
You will get an error because your variable x
is not optional and you didn't provide any value for it so you have to write an init OR set an initial value.
class A {
var x: Int // Write init or set a value here
init() {
x = 0
}
}
I strongly recommend you to read the section about initialization in Apple Docs.
Getting around automatic initializer inheritance rules Swift
You should (and must) always call a designated initializer. That's what it means to be the designated initializer. If your designated initializer is init(value:)
, then init(name: String?, uid: String?, email: String?, username: String?)
should be a convenience initializer that calls it. Implementing a new "must-call" (i.e. designated initializer) means that the superclass's designated initializer is invalid for this subclass, but that's not the case here. So just write:
convenience init(name: String?, uid: String?, email: String?, username: String?) {
self.init(values: ["name": name, "uid": uid, "email": email, "username": username])
}
This shouldn't invalidate your other inits.
Can a subclass not inherit the superclass' initializer and when do we use the required initializer?
Try and think about it in terms of what initialization does for an object. It sets values to parameters that do not have values set to them yet that need values set before use. See: https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID228. So each class needs to have a way to initialize it and if necessary deal with setting variables or passing that responsibility along the subclass chain. The required init() function should be used as a unique case where somewhere in the initialization chain a special property is computed/set in required init() of a super class that makes it a requirement to call required init() in a subclass/subclasses of it. You do not need to write override required in this case.
Why do we override initializers in Swift?
Subclasses might not inherit their superclass initializers "by default", but they can be inherited (e.g. if you don't supply any designated initializers, you will automatically inherit all of the designated initializers of the superclass ... see Automatic Initializer Inheritance).
Consider a Dog
subclass called Chihuahua
: If you don't implement any designated initializers in Chihuahua
, you automatically inherit the Dog
initializers with no extra code on your part. But if you do need to override it for some reason, do so and you just need to call a Dog
designated initializer from your Chihuahua
designated initializer. And if your Chihuahua
initializer has the same signature as a Dog
designated initializer, then you must explicitly supply the override
keyword.
Check designated initializer in xcode
In Swift, any initializer not marked with the keyword "convenience" is a designated initializer.
And designated initializers are required to call a designated initializer in their immediate superclass, per The Swift Programming Language. They cannot call a convenience initializer.
What's the difference between a required initializer and a designated initializer?
Required initialisers and designated initialisers are not really related, though the associated keywords required
and convenience
are both used to specify restrictions on subclasses.
Required Initialisers
A required initialiser makes a guarantee that you can initialise a type, or any of its sub-types, with that initialiser. If you have an initialiser in a protocol and you conform something to that protocol, you have to use required
(if it's a class) because that protocol guarantees that the initialiser is present on that class, and any of its subclasses. When you use required
on an initialiser of a class, that signals that all of its subclasses can also be initialised using that method. This means you also need to add that initialiser to any of its subclasses.
protocol TestProtocol {
init()
}
class TestClass: TestProtocol {
required init() {
}
}
Here, the required
keyword must be present because any subclasses of TestClass
must also provide init()
(because they also conform to TestProtocol
).
Having a required initialiser allows you to initialise a class without knowing what it is at compile time, which is useful for a variety of reasons:
let classType: TestProtocol.Type = TestClass.self
let object = classType.init()
If your class conformed to multiple protocols, each with a different initialiser for example, each of those initialisers must also be required:
protocol OtherProtocol {
init(thing: Int)
}
class OtherClass: TestClass, OtherProtocol {
let thing: Int
required init() { // Required from superclass/its protocol
self.thing = 0
}
required init(thing: Int) { // Required from new protocol
self.thing = thing
}
}
Note that adding super.init()
isn't required in this special case, because Swift will automatically include the call if it takes no parameters.
In all the above examples, the initialisers are designated because they do not include the convenience
keyword.
Even if you didn't have any protocols, you can still make use of required
by initialising a type of a class which isn't known at compile time:
class BaseClass {
let value: Int
required init(value: Int) {
self.value = value
}
}
class SubClass: BaseClass {
required init(value: Int) { // Required from superclass
super.init(value: value) // Must call desginated initialiser of superclass
}
}
let someBaseClassType: BaseClass.Type = SubClass.self
let someBaseClassInstance = someBaseClassType.init(value: 1)
Designated Initialisers
A designated initialiser is one which isn't a convenience initialiser (i.e, marked with convenience
). A designated initialiser must make sure that all properties of the class have a value before the initialiser finishes (or a super initialiser is called). Convenience initialisers only don't have this requirement because they must themselves call a designated initialiser.
class OtherSubClass: BaseClass {
convenience required init(value: Int) {
self.init() // Must call designated initialiser of this class
}
init() {
super.init(value: 0) // Must call designated initialiser of superclass
}
}
(This is fairly contrived example.)
In my experience, convenience initialisers are rarely useful and I tend to find the problems they solve can be solved using optional arguments on designated initialisers instead. One also needs to consider the fact that initialisers can't call convenience initialisers on their superclass, so make sure you don't have any convenience initialisers which provide functionality that your designated initialisers don't if you intend your class to be subclassed!
Structs and enums don't use the required
or convenience
keywords because these keywords are both used to indicate initialisation rules for subclasses, which only class
es support: The required
keyword indicates that subclasses must provide that initialiser, and the convenience
keyword indicates that subclasses cannot call that initialiser. Despite not having the keywords, they must still provide initialisers defined in any protocols they conform to, and you can write 'convenient' initialisers which call self.init
, just without the convenience
keyword.
To respond to your statements:
- Required initialisers don't have to be designated.
- Designated initialisers don't have to be required.
- Classes can have multiple required and designated initialisers.
Related Topics
How to Upload Images from The Browser to Amazon S3 Using Vapor and Leaf
Using Auto Layout to Orientate Stack Views Vertically in Portrait and Horizontally in Landscape
How to Use This Fetchrequest() in Swift
Apple's Swift Compiler Complains of Partial Application When Creating Extension Method on Array
How to Enable a Button in Different Cases in Swift
Swiftui Previews - Unexpected Data
Swift 4 JSONdecoder Optional Variable
Non-Translucent UItabbar Creates Strange Grey Bar
Leaks in Navigationview/List/Foreach with Dynamically Generated Views
Map Dictionary Keys to Add Values - Swift
Swiftui Textfield Resets Value and Ignores Binding
Parse Nested Completion Handlers
Command Center Scrubber on Lock Screen Swift
Onreceive String.Publisher Lead to Infinite Loop
Synchronous Request Using Alamofire
Cannot Divide and Assign Int64 Value