Reputation: 561
Swift has no abstract classes and methods. Instead, it offers protocols.
That's fine when your classes are either fully abstract or fully concrete.
But what is the best 'Swift' way to implement an abstract class that also has concrete methods?
Pseudo-code example:
class Animal {
abstract makeSound()
abstract eyeCount()
}
class Mammal : Animal {
override eyeCount { return 2 } // Let's assume all mammals have hard-coded 2 eyes...
class Cat : Mammal {
override makeSound { print "Meow!" }
}
class Dog : Mammal {
override makeSound { print "Woof!" }
}
In Mammal, I do want to implement the concrete method eyeCount()
because all mammals have 2 hard-coded eyes (supposedly) and I don't want to re-implement it in dog and cat. However, makeSound()
should only be implemented for Dog and Cat as mammals have varying voices.
How would you implement this in Swift? Thanks!
Upvotes: 7
Views: 3453
Reputation: 181
You can use Protocol Extensions to get the exact same behavior as with Abstract Classes: Checking if abstract methods are implemented in subclasses at compile time.
protocol Entity {
// MARK: - Abstract methods
func filename() -> String
// MARK: - Traits
func saveData(data: NSArray)
}
extension Entity {
func saveData(data: NSArray) {
// Do something and call:
let filename = filename()
}
}
Now you can implement the Entity
protocol on a Subclass and the compiler will force you to implement filename()
while the saveData()
method is already implemented.
Upvotes: 6
Reputation: 9586
I would implement it like this:
class AbstractAnimal
{
// Fully abstract method
func methodThatReturnsSomething() -> String {
fatalError("methodThatReturnsSomething() is abstract and must be overriden!");
}
func eyeCount() -> Int {
return 2;
}
}
fatalError
prevents Xcode from complaining that abstract method methodThatReturnsSomething()
doesn't actually return anything.
Upvotes: 5
Reputation: 22939
One way you could do this, as suggested by @BobDickinson in Abstract functions in Swift Language, is the following:
protocol Animal {
var eyeCount: Int { get }
func makeSound()
}
// Note - `Mammal` doesn't conform to `Animal`.
class Mammal {
let eyeCount = 2
}
// Only `Cat` and `Dog` conform to `Animal`, so only they need to implement `makeSound`.
class Dog: Mammal, Animal {
func makeSound() {
println("Woof")
}
}
class Cat: Mammal, Animal {
func makeSound() {
println("Meow")
}
}
Upvotes: 0
Reputation: 5536
A common method to do this is to have an abstract class that has concrete methods in it. All classes can subclass this abstract class to inherit the concrete methods as well as abstract methods.
UIGuestureRecognizer
and UIGuestureRecognizerSubclass
is a very good example of this. Because this is intended for subclassing, this abstract class contains many internal concrete methods as well as subclassable abstract methods for you to implement.
This is a common pattern for many Swift and Objective-C projects.
Upvotes: 0