Hatchmaster J
Hatchmaster J

Reputation: 561

Swift - mixing abstract and concrete methods

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

Answers (4)

pommes
pommes

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

BadmintonCat
BadmintonCat

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

ABakerSmith
ABakerSmith

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

Schemetrical
Schemetrical

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

Related Questions