How to Create an Abstract Class in Swift
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 returnstrue
if an instance conforms to a protocol and returnsfalse
if it doesn’t. -
The
as?
version of the downcast operator returns an optional value of the protocol’s type, and this value isnil
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: