Implementing Swift Protocol Methods in a Base Class

Implementing Swift protocol methods in a base class

This should work:

protocol MyProtocol {
class func retrieve(id:String) -> Self?
}

class MyBaseClass: MyProtocol {

required init() { }

class func retrieve(id:String) -> Self? {
return self()
}
}

required init() { } is necessary to ensure any subclasses derived from MyBaseClass has init() initializer.

Note that this code crashes Swift Playground. I don't know why. So try with real project.

Swift override protocol methods in sub classes

Use protocol extension with where clause. It works.
But I would not recommend you to have such things in your codebase.

class BaseViewController: UIViewController {

}

extension OptionsDelegate where Self: BaseViewController {
func handleSortAndFilter(opt: Options) {
print("Base class implementation")
}
}

extension BaseViewController: OptionsDelegate {

}

class InsipartionsViewController: BaseViewController {

}

extension OptionsDelegate where Self: InsipartionsViewController {
func handleSortAndFilter(opt: Options) {
print("Inspirations class implementation")
}
}

Add protocol to super class which will force other classes that inherit from it to implement protocol

What you are looking for is an abstract class. The purpose of an abstract class is to behave as a base class for concrete classes to inherit from, but an abstract class cannot be instantiated directly.

If Employee was an an abstract class then any attempt to actually instantiate an instance of Employee would be reported as an error by the compiler. You would need to instantiate a concrete subclass of Employee, such as SalariedEmployee or HourlyEmployee.

The definition of the Employee class would include that the calculatePay method was required and again a compile time error would occur if a concrete subclass did not implement that method.

Now, the bad news. Neither Objective-C nor Swift supports abstract classes.

You can provide a similar kind of class by providing an implementation of a method that throws an exception if it isn't overridden by a subclass. This gives a runtime error rather than a compile time error.

e.g.

class Employee {
var givenName: String
var surname: String
...

init(givenName: String, surname: String) {
self.givenName = givenName
self.surname = surname
}

func calculatePay() -> Float {
fatalError("Subclasses must override calculatePay")
}
}

class SalariedEmployee: Employee {

var salary: Float

init(givenName: String, surname: String, annualSalary: Float) {
salary = annualSalary
super.init(givenName: givenName, surname: surname)
}

override func calculatePay() -> Float {
return salary/12 // Note: No call to super.calculatePay
}

}

Whether the calculatePay is part of the base class or assigned to the base class through an extension that adds conformance to a protocol, the result is the same;

  • The Employee class will need a default implementation of the function that generates some sort of error
  • Failure of a subclass to implement the method will not cause a compile time error

You could assign a protocol, say, Payable to each subclass individually, but then as the protocol was not part of the base class, you couldn't say something like:

 var employees[Employee]

for e in employees {
let pay = e.calculatePay()
}

You would have to use the slightly more complicated:

 for e in employees {
if e is Payable {
let pay = e.calculatePay()
}
}

How is it possible that class is implementing only methods(protocol) that it needs?

This means b() and c() have default implementations. If you search for extension MyProtocol in the codebase you should be able to find their default implementations.

Swift: Abstract base class/protocol with private members

When I need an abstract base with some properties/functions hidden I use class with some additional fatalErrors and asserts to crash whenever someone is trying to use Base instead of implementation.

public class AbstractBase {
init() {
assert(type(of: self) != AbstractBase.self, "Abstract class")
}

fileprivate var _constant: Int {
fatalError("Abstract class")
}
fileprivate func _operation(_ val: Int) -> Int {
fatalError("Abstract class")
}

func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}

public class ConcreteSub: AbstractBase {

fileprivate override var _constant: Int {
return 42
}
fileprivate override func _operation(_ val: Int) -> Int {
return val + 2
}
}

How to properly implement the Equatable protocol in a class hierarchy?

After lots of research and some trial and error I finally came up with a working solution. The first step was moving the == operator from inside the class to the global scope. This fixed the errors about static and final.

For the base class this became:

func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}

class Base : Equatable {
var x : Int
}

And for the subclass:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
return true
}

class Subclass : Base {
var y : String
}

Now the only part left is figuring out how to call the == operator of the base class from the == operator of the subclass. This led me to the final solution:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}

return false
}

That first if statement results in a call to the == operator in the base class.


The final solution:

Base.swift:

func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}

class Base : Equatable {
var x : Int
}

Subclass.swift:

func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}

return false
}

class Subclass : Base {
var y : String
}


Related Topics



Leave a reply



Submit