How to Create an Abstract Class in Swift

protocols, protocol extension, protocol conformance

How to Create an Abstract Class in Swift

protocols, protocol extension, protocol conformance

There are no abstract classes in Swift (just like Objective-C). Your best bet is going to be to use a Protocol, which is like a Java Interface. With Swift 2.0, you can then add method implementations and calculated property implementations using protocol extensions. Your only restrictions are that you can’t provide member variables or constants and there is no dynamic dispatch.

Protocols

How It Works

Protocols are nothing new if you’re familiar with Objective-C. To illustrate this solution, The following example defines a protocol with a single instance method requirement:

protocol RandomNumberGenerator {
func random() -> Double
}

This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it’s called.

Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator:

Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

For example, the RandomNumberGenerator protocol can be extended to provide a randomBool() method, which uses the result of the required random() method to return a random Bool value:

extension RandomNumberGenerator {
 func randomBool() -> Bool {
 return random() > 0.5
 }
}

By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification.

Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol. Protocol inheritance is always specified in the protocol declaration itself.

Another example of this technique would be:

protocol Employee {
var annualSalary: Int {get}
}
extension Employee {
var biweeklySalary: Int {
return self.annualSalary / 26
}
    func logSalary() {
print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
}
}
struct SoftwareEngineer: Employee {
var annualSalary: Int
    func logSalary() {
print("overridden")
}
}
let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly

Notice that this is providing “abstract class” like features even for structs, but classes can also implement the same protocol.

Also notice that every class or struct that implements the Employee protocol will have to declare the annualSalary property again.

Most importantly, notice that there is no dynamic dispatch. When logSalary is called on the instance that is stored as a SoftwareEngineer it calls the overridden version of the method. When logSalary is called on the instance after it has been cast to an Employee, it calls the original implementation (it doesn't not dynamically dispatch to the overridden version even though the instance is actually a Software Engineer.

Checking for Protocol Conformance

You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:

  • The is operator returns true if an instance conforms to a protocol and returns false if it doesn’t.
  • The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance doesn’t conform to that protocol.
  • The as! version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast doesn’t succeed.

References:

  1. https://docs.swift.org/swift-book/