@dpalme,
Take a look at the inter-relationships between these classes:
class Animal {
func importantMethod() {
print("importantMethod")
}
}
class Dog: Animal {
var myWorker: DogOwner
init(worker: DogOwner) {
myWorker = worker
}
func go() {
importantMethod()
myWorker.walkDog()
myWorker.feedDog()
}
}
//--
class Human {
func importantMethod() {
print("importantMethod")
}
}
class DogOwner: Human {
var name: String
init(name: String) {
self.name = name
}
func walkDog() {
print("walkDog")
}
func feedDog() {
print("feedDog")
}
func goToMovies() {
importantMethod()
print("goToMovies")
}
}
In the Dog class, take special note of the following line:
var myWorker: DogOwner
The problem with that line is that the Dog class can only work in conjunction with a DogOwner type. But ponder this: does a dog care who walks it and who feeds it? For instance, can a Nanny walk a dog and feed a dog? Can a Child walk a dog and feed a dog? Can a Robot walk a dog and feed a dog? Yes, they can! But, as currently written the Dog class can’t work in conjunction with a Nanny, or a Child, or a Robot object because the Dog class specifies the type of myWorker as DogOwner. Ideally, the Dog class should really only care that the myWorker object can perform the necessary tasks. That is where Swift protocols come into play: a protocol allows you to specify what functions that an object must perform.
-
A protocol defines a type, which means you can declare a variable that has the protocol type.
-
A protocol can define a set of functions that an object of the protocol type must implement.
Here’s how a protocol can be employed with the Dog class:
...
...
protocol DogWorker {
func walkDog()
func feedDog()
}
class Dog: Animal {
var myWorker: DogWorker //<=== HERE
init(worker: DogWorker) {
myWorker = worker
}
func go() {
importantMethod()
myWorker.walkDog()
myWorker.feedDog()
}
}
...
...
Now, examine this line again:
var myWorker: DogWorker
By declaring myWorker to be of type DogWorker, the Dog class is now specifying a set of functions that myWorker must be able to perform. The benefit is that now a Dog class can work in conjunction with any class that has the type DogWorker, for instance:
class Nanny: Human, DogWorker {
func watchChild() {
importantMethod()
print("watchChild")
}
func walkDog() {
print("walkDog")
}
func feedDog() {
print("feedDog")
}
}
---
class Robot {
func importantMethod() {
print("importantMethod")
}
}
class HouseholdRobot: Robot, DogWorker {
func walkDog() {
print("walkDog")
}
func feedDog() {
print("feedDog")
}
func getMonthlyService() {
importantMethod()
print("getMonthlyService")
}
}
Note that Swift does not allow multiple inheritance, and the inheritance structures in the example are already packed with parent classes. Therefore, you cannot create a DogWorker class and have the DogOwner, Nanny, and HouseholdRobot classes inherit from the DogWorker class.
The only solution that will make the Dog class more general and useful, and allow the Dog class to work in conjunction with a wider range of objects, is to create a protocol. Then the Dog class can declare its myWorker variable to be the protocol type, which will allow any class that implements the protocol to work with the Dog class.
In iOS, a UITableView employs the same strategy outlined above. A UITableView has a variable called dataSource
, and the UITableView declares the dataSource variable to have the type of a protocol. That allows your ViewController class, which already has a parent class, e.g. UITableViewController, to adopt the protocol so that it can work in conjunction with the UITableView. When you control drag from a UITableView to your ViewController and hook up the dataSource connection, you are telling iOS to assign an instance of your ViewController to the UITableView’s dataSource variable. Then the UITableView uses the dataSource variable to call “worker” methods that you implemented in your ViewController.
Single inheritance with protocols is an architecture that you can find in Java as well (in Java they’re called interfaces). That architecture contrasts with C++, which allows multiple inheritance.