Overriding superclass initializer in Swift - 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()
}

Related

In swift, how to access methods of class A inside class B if class B inherits from class A?

Examples for creating mocked classes, methods and protocols would be helpful.
It was answered dozen of times. Here's the extract from one of the answers I gave on equivalent topic, slightly adjusted.
When you have class B derived from class A...
class ClassA: UIViewController {
func myFunc() { print("...") }
}
class ClassB: ClassA {
}
In class B, you can call a method from class A by typing
super.myFunc() **OR** self.myFunc()
...depending on whether or not you have re-implemented that method in a subclass with override keyword. If you did not override it (and you don't necessarily have to), then those two calls are equivalent.
On the other hand, if you added your own implementation in B:
override func myFunc() {
print("My implementation of myFunc")
}
calling super.myFunc() will call implementation from A. And calling self.myFunc() will call your local implementation, both being acceptable from your subclass. And when your subclass calls super as well:
override func myFunc() {
super.myFunc()
print("My implementation of myFunc")
}
calling self.myFunc() from subclass will call implementation from both. Keep in mind, that if you don't call superclass implementation in your override method, you replace this implementation.
In most UI-classes, it's highly recommended to call superclass method upon overriding, in order to avoid any abnormal behavior, unless you provide sufficient implementation on your own (e.g. reposition or draw elements).
P.S. Mocks and unit-testing is the entire solid topic, simply impossible to cover in single post. Please, learn!

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

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.

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.

Issue with the call hierarchy of a swift protocol extension

I've implemented a little wrapper for Alamofire's reachability. Now I ran into an issue with a subclass not receiving notifications.
As dfri added in a comment, the problem can be described as a superclass method invoked by a subclass instance does not see an overridden subclass method if it is placed in an extension.
Thanks for his excellent gist showing the reproducible problem with the usual foo/bar: https://gist.github.com/dfrib/01e4bf1020e2e39dbe9cfb14f4165656
The protocol & extension logic:
protocol ReachabilityProtocol: class {
func reachabilityDidChange(online: Bool)
}
extension ReachabilityProtocol {
func configureReachabilityManager() {
// triggered externally:
rechabilityManager?.listener = { [weak self] status in
self?.reachabilityDidChange(online)
}
}
func reachabilityDidChange(online: Bool) {
// abstract, implement in subclasses
}
}
Now ViewController A adopts this protocol and implements the method:
class A: UIViewController, ReachabilityProtocol {
func reachabilityDidChange(online: Bool) {
debugPrint("123")
}
}
Working until here, prints 123.
ViewController B is a subclass and overrides the method from A:
class B: A {
override func reachabilityDidChange(online: Bool) {
super.reachabilityDidChange(online)
debugPrint("234")
}
}
Working, too. Prints now 234 and 123 upon notification.
Now the tricky part, in terms of structuring the code, the overriden method got moved into an own extension inside of B (same swift file as class B):
class B: A {
...
}
// MARK: - Reachability Notification
extension B {
override func reachabilityDidChange(online: Bool) {
super.reachabilityDidChange(online)
debugPrint("234")
}
}
Now B's reachabilityDidChange() isn't called anymore. Output is just 123.
To check the logic I even tried to remove the override keyword: the compiler immediately complains about needing it.
So from what I can say the call hierarchy is correct. Visibility too.
Subsumption: If the method overridden is placed into it's own extension, it's not visible/invoked anymore but the compiler still requires the override keyword.
That's something I didn't came across yet, or it's me working to long on the same project today..
Any hints?
Overriding superclass methods in extensions: only allowed for Objective-C compatible methods
First of all we note that you can only override a superclass method in an extension of a subclass if the method is Objective-C compatible. For classes deriving from NSObject, this is true for all instance methods (which is true here, as UIViewController derives from NSObject). This is covered in e.g. the following Q&A:
Can you override between extensions in Swift or not? (Compiler seems confused!)
Enforcing dynamic dispatch via Objective-C runtime
Now, from Interoperability - Interacting with Objective-C APIs - Requiring Dynamic Dispatch, we note the following
When Swift APIs are imported by the Objective-C runtime, there are no
guarantees of dynamic dispatch for properties, methods, subscripts, or
initializers. The Swift compiler may still devirtualize or inline
member access to optimize the performance of your code, bypassing the
Objective-C runtime.
You can use the dynamic modifier to require that access to members be
dynamically dispatched through the Objective-C runtime.
Moreover, from The Language Ref. - Declarations - Declaration Modifyers we read
dynamic (modifier)
Apply this modifier to any member of a class that can be represented
by Objective-C. When you mark a member declaration with the dynamic
modifier, access to that member is always dynamically dispatched using
the Objective-C runtime. Access to that member is never inlined or
devirtualized by the compiler.
Because declarations marked with the dynamic modifier are dispatched
using the Objective-C runtime, they’re implicitly marked with the objc
attribute.
Enforcing dynamic dispatch for reachabilityDidChange(...) in A
Hence, if you add the dynamic modifier to method reachabilityDidChange(...) in your superclass A, then access to reachabilityDidChange(...) will always be dynamically dispatched using the Objective-C runtime, and hence find and make use of the correct overridden reachabilityDidChange(...) method in the class B extension, for instances of B. Hence,
dynamic func reachabilityDidChange(online: Bool) { ... }
in A will fix the above.
Below follows a more minimal example of your issue above, redeemed by demanding dynamic dispatch via obj-c runtime for method foo() in class A (equivalent to your method reachabilityDidChange(...) in class A).
import UIKit
protocol Foo: class {
func foo()
}
extension Foo {
func foo() { print("default") }
}
class A: UIViewController, Foo {
dynamic func foo() { print("A") } // <-- note dynamic here
func bar() { self.foo() }
/* \
hence, foo() is dynamically dispatched here, and for
instances where "self === B()", this is correctly
resolved as the foo() in the extension to B */
}
class B : A { }
extension B {
override func foo() {
super.foo()
print("B")
}
}
let a = A()
a.bar() // A
let b = B()
b.bar() // A B
/* or, only "A" if not using dynamic dispatch */

Initializers from generic types won't be inherited in swift?

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.