Swift initializer inheritance - swift

Can you tell me why the superclass initializer gets called because I never call it from the initializer in subclass ?
Regarding the two step process of the initialization, I thought that the compiler would throw an error because I didn't call super.init() actually
class Superclass {
var a: Int
init() {
self.a = 1
}
}
class Subclass: Superclass {
var b: Int
override init() {
self.b = 2
}
}
var subclass = Subclass()
print(subclass.b)
// Print 2
print(subclass.a)
// Print 1 => How is it possible as I never call super.init() ?

The compiler can synthesise a call to super.init() in a designated initialiser if you don't make the call yourself. So in your case the compiler effectively transforms your code to:
class Superclass {
var a: Int
init() {
self.a = 1
}
}
class Subclass : Superclass {
var b: Int
override init() {
self.b = 2
super.init() // synthesised by the compiler
}
}
This also applies to cases where you're not overriding the superclass' init():
class Subclass : Superclass {
var b: Int
init(b: Int) {
self.b = b
super.init() // also synthesised by the compiler (try removing)
}
}
Note that this synthesis comes with some restrictions, it only applies when:
The superclass has one and only one designated initialiser
This designated initialiser doesn't have any parameters, i.e init()
In all other cases you need to call super.init yourself.

Related

Swift variable observers not called before super.init called

Okay so I was reading up on how willSet/didSet are used in swift and I came across a note on apples swift docs that just doesn't make any sense to me and I hope someone can explain. Here's the note:
The willSet and didSet observers of superclass properties are called
when a property is set in a subclass initializer, after the superclass
initializer has been called. They are not called while a class is
setting its own properties, before the superclass initializer has been
called.
From: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
What confuses me is that they point out that the observers on superclass A properties in a subclass B aren't called before the super.init call by B to A.
class A {
var p: Bool
init() {
p = false
}
}
class B: A {
override var p: Bool {
didSet {
print("didSet p")
}
}
override init() {
p = true // Compiler error
super.init()
}
}
However the property is never even accessible in that time from either A nor B, so who's gonna call the observers anyway? Attempting to read/write the property will even result in a compiler error so it's never even possible to do it by mistake in Swift. Am I missing something or is this just a misleading note that points out the wrong thing?
They are talking about following scenario:
class A {
var p: Bool {
didSet {
print(">>> didSet p to \(p)")
}
}
init() {
p = false // here didSet won't be called
}
}
class B: A {
override init() {
// here you could set B's properties, but not those inherited, only after super.init()
super.init()
p = true // here didSet will be called
}
}
B()
It will print following:
>>> didSet p to true
While to you it might seems natural, the documentation has to explicitly document this behavior.

Swift: Implementing Protocol Initializer in a Class

I am trying to understand why Swift enforces a class that conforms to a protocol with an initializer to be marked as required. This essentially enforces any subclasses to also implement that initializer. Surely the designated superclass initializer would be inherited?
The quotes below are taken from the Swift Language Guide:
https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID272
You can implement a protocol initializer requirement on a conforming
class as either a designated initializer or a convenience initializer.
In both cases, you must mark the initializer implementation with the
required modifier:
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init(someParameter: Int) { // enforced to implement init again
// initializer implementation goes here
}
}
The use of the required modifier ensures that you provide an explicit
or inherited implementation of the initializer requirement on all
subclasses of the conforming class, such that they also conform to the
protocol.
EDIT:
I had not initially mentioned that I am currently limited to Swift 2.1. It appears to be a compiler issue in this release and does not occur in later versions.
Surely the designated superclass initializer would be inherited?
No, not always. If the subclass defines its own designated initialisers, then it won't automatically inherit the superclass' designated initialisers. Consider the following example:
class Foo {
init() {}
}
class Bar : Foo {
var str: String
init(str: String) {
self.str = str
}
}
let b = Bar() // illegal – what value would the 'str' property have?
As Bar defines its own init(str:) designated initialiser, it doesn't automatically inherit Foo's designated initialiser init(). This prevents unsafe initialisation in cases where the subclass declares its own stored properties.
Marking init() as required enforces Bar has an init(), be it through providing its own implementation:
class Foo {
required init() {}
}
class Bar : Foo {
var str: String
init(str: String) {
self.str = str
}
// implement required init(), as Bar defines its own designated initialiser.
required init() {
self.str = "foo" // now str is correctly initialised when calling init()
}
}
let b = Bar() // now legal
Or by inheriting Foo's implementation (when Bar doesn't define its own designated initialisers):
class Foo {
required init() {}
}
class Bar : Foo {
// inherits init() from Foo, as Bar doesn't define its own designed initialisers.
}
let b = Bar() // legal
You're not force to implement the initializer in the subclass. Consider this example, which compiles just fine:
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
print(someParameter)
}
}
class SomeSubclass: SomeClass {
// Notice that no inits are implemented here
}
_ = SomeClass(someParameter: 123)
_ = SomeSubclass(someParameter: 456)

Adding a failable initializer with the same signature as super class's convenience initializer (Swift)

I would like to know why I cant define init?() for SubView. Compiler warms me with Failable initializer 'init()' cannot override a non-failable initializer. But for my understanding convenience init is not treat as override in subclass as compile will warm me if I add override to init?() with Initializer does not override a designated initializer from its superclass.
My expectation for SubView.init?() is that it should not treat as a override to View.init() as SubView should not have that convenience initializer inherited as SubView.init() in the first place.
import Foundation
import UIKit
class View {
convenience init() {
self.init(frame: CGRectZero)
}
init(frame: CGRect) {
}
required init?(coder aDecoder: NSCoder) {
}
}
class SubView: View {
private var value: String!
init?() {
super.init(frame: CGRectZero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
see this 'self explanatory' example
class Base {
var i:Int
init?(i: Int){
self.i = i
if i == 0 {
return nil
}
}
convenience init() {
self.init(i: 1)!
}
}
class C: Base {
override init?(i: Int){
super.init(i: 2 * i)
}
}
var c: C? = C() // C automatically inherits convenience init() from its superclass
c?.i == 2 // true !!!!!
// that is why
class D: Base {
init?() {
// error: failable initializer 'init()' cannot override a non-failable initializer
}
}
UPDATE
from our discussion i think, that the 'missing glue' in proper understanding initialization in Swift is interpretation of 'convenience' attribute / keyword. what is the difference between init() and convenience init() ? if we don't provide any designated initializer, Swift use the default one, which can be interpreted with signature init(){} /no parameters/. if we define our own version of init(){ .... }, compiler will use our version. in designated init(){ ... } or init?(){ ... } we are NOT able to reference self, in convenience init(){ ... } or convenience init?() { ... } we can and mostly we do it. Otherwise convenience is not necessary there. Which initializer could compiler to use, if we are going to define two of them with the same signature /same parameters/? There is no chance to choose for it!
// your expectation is wrong,
// because initializer is NOT like other methods
class C {
var i: Int?
// this compiles here, but see the usage below!
func foo()->Int {
i = 1
return i!
}
func foo()->Int? {
i = nil
return i
}
// convenience or not, it doesn' matter
init() {
i = 1
}
// with next lines compiler complains
// because they all have the same signature / same parameters /
// from you code you call all three initializers
// the same way
//
// let c = C()
//
// dynamicType of c depends of the relsut of class constructor (initializer).
// this result is anyway the REFERENCE, not a value.
// c will be a variable or constant (probably an optional) which value will
// be the REFERNCE to created instance (and probably 'null reference')
// nil is special value in Swift and differs from 'null reference'
// in case of fail-able initializer the c must be Optional or ImplicitlyInwrappedOptional
/*
convenience init?() {
self.init()
}
init?() {
return nil
}
*/
}
let c = C()
let p1: Int = c.foo() // 1
let p2: Int? = c.foo() // nil
//let p = c.foo() // error: ambiguous use of 'foo()'
class D {
var i:Int?
init() {
i = 1
}
}
// by the theory, compiler could be 'smart' enough to choose the
// right version of initializer, but it could have very strong
// consequences to the language as well.
let d1: D = D()
let d2: D? = D()
d1.i // 1
d2?.i // 1
// but only one is valid if we use fail-able version of init
class E {
var i:Int?
init?() {
i = 1
}
}
let e1: E? = E()
e1?.i // 1
//let e2:E = E() // error: value of optional type 'E?' not unwrapped

Cannot override initialiser in subclass of generic class

I'd like to make a subclass of a generic class that is itself a subclass but I cannot override the initializer.
To clarify:
class BaseClass {
init(printMe: String) {
print(printMe)
}
}
class GenericClass<T>: BaseClass {
var object: T?
}
class NotGenericClass: GenericClass<NSNumber> {
override init(printMe: String) { // <- Error here
super.init(printMe: printMe)
// More setup
}
}
let a = NotGenericClass(printMe: "Print this")
a.object = NSNumber(int: 1)
The override init(printMe: String) line in NotGenericClass gives the following error:
Initializer does not override a designated initializer from its superclass
If GenericClass did not take a type parameter, this code would work. Is this a bug with Swift or am I misunderstanding how subclassing generic classes should work?
It seems that GenericClass doesn't automatically inherit the initializer in this case.
This makes it work:
class GenericClass<T>: BaseClass {
var object: T?
// Explicitly provide an initializer
override init(printMe: String) {
super.init(printMe: printMe)
}
}
This isn't clear from the Automatic Initializer Inheritance section of the docs, which claims that "If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers". You might want to file a bug.

Why you need to add empty constructors for UIViewController subclass in Swift

Why I need to add these constructors (empty) even if I will not add some custom initialisation things into UIViewController subclass?
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
In Swift, unlike some languages, a subclass does not normally inherit its superclass's initializers. Automatic initializer inheritance can only take place under certain conditions. Given a class A:
class A {
var a: Int
var r: Int
init(a: Int) {
self.r = 0
self.a = a
}
}
A class B automatically inherits initializers only if both of the following conditions are met:
a. All newly introduced properties of the subclass are have been assigned default values.
b. No new designated initializers have been introduced into the subclass, or any newly introduced initializers provide their own implementation of superclass initializers:
//All values assigned, no additional initializers
class C: A {
var c: Int = 9
}
//Provides an implementation of class A's initializer
class B: A {
init() {
super(a: 0)
}
}
Now if we introduce a required initializer into a class, things get hairy.
class AWithRequired {
var a: Int
var r: Int
init(a: Int) {
self.r = 0
self.a = a
}
required init(a: Int, r: Int) {
self.r = r
self.a = a
}
}
In this case we can't introduce any non-designated initializers without also overriding the required initializer:
//Still OK--no new initializers introduced
class BWithRequired: AWithRequired {
var b: Int = 9
}
//Doesn't ovverride required initializer, throws an error
class CWithRequired: AWithRequired {
init() {
super.init(a: 0, r: 0)
}
} //ERROR: Required Initializer must be supplied by subclass of 'AWithRequired'
//OK, overrides required initializer
class DWithRequired: AWithRequired {
required init(a: Int, r: Int) {
super.init(a: 0, r: 0)
}
}
//OK, provides non-designated initializer
class EWithRequired: AWithRequired {
convenience init() {
self.init(a: 0, r: 0)
}
}
As you can see from the examples, the only way to get around the restriction and still implement a custom initializer is to introduce a non-designated, e.g. convenience initializer.
To avoid this, when initializing new variables in your class, you need to assign them.
Example:
class yourTestClass
{
var testString:String = ""
//or
var testStringTwo:String = String()
}