If I understand your question correctly, maybe this well help.
you can give bark() a default implementation by extending the protocol. Then on other classes that conform to the protocol you can change the implementation of the bark function:
protocol Bark {
func bark()
}
//default implementation
extension Bark {
func bark() { print("Bark") }
}
class Dog: Bark {}
//By calling bark func in Poodle, you change the default implementation.
class Poodle: Dog {
func bark() { print("Yap") }
}
class GermanShephard: Dog {
func bark() { print("Woof") }
}
let dog = Dog()
let poodle = Poodle()
let germanShephard = GermanShephard()
dog.bark()
//Bark
poodle.bark()
//Yap
germanShephard.bark()
//Woof
You can also not do any default implementation and just add your own for each situation
Edit after comment:
This is one of the main reason protocols are useful. They remove the tight coupling involved with subclassing. This is a base example as the entire topic is a lot of info but rather than subclassing Dog you can make a protocol DogRepresentable and assign all the default proprties and functions that all dogs implement the same. Then you can extend DogRepresentable where self: UIViewController and implement the default functionality:
protocol Barkable {
func bark()
}
protocol DogRepresentable: Barkable {
//properties and functions all dogs will have with same implementation
}
extension DogRepresentable where Self: UIViewController {
//default implementation for functions all dogs will use
}
By assigning Barkable to DogRepresentable, you know any class that conforms to DogRepresentable will also have to conform to Barkable.
Now when you assign DogRepresentable to a class, it will get all the default implementation a base class would get, and you are forced to call the bark() function to conform to the protocol properly:
class Dog: DogRepresentable {
func bark() { print("Bark") }
}
class Poodle: DogRepresentable {
func bark() { print("Yap") }
}
class GermanShephard: DogRepresentable {
//Won't conform because it doesn't have bark()
}
This way you get all the default implementation like the base class but won't have the issue of forgetting to override the superclass function.
Edit 2 based on second comment:
In that case your best bet is to leave DogRepresentable without conforming to Barkable and then create protocols for different types: so if you have dogs that yap you could do a protocol Yappable which has a bark function and default implementation. Then you can have another protocol Barkable with its own bark function and its own default implementation. Then have the class conform to whichever protocol they should conform to. Poodle conforms to Yappable, Dog conforms to Barkable.
By creating these separate protocols you can keep the functionality for each situation in one spot and only use whichever one you need, keeping your code cleaner, more readable, and DRY.