Programming in Swift: Functions & Types

Jan 4 2022 · Swift 5.5, iOS 15, Xcode 13

Part 5: Protocols & Inheritance

39. Challenge: Inheritance

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 38. Inheritance Next episode: 40. Initializers

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 39. Challenge: Inheritance

Update Notes: This course was originally recorded in 2019. It has been reviewed and all content and materials updated as of October 2021.

Transcript: 39. Challenge: Inheritance

I’ve got an inheritance challenge for you! Again, everything you need is in the playground for this part of the course. Pause the video, and do your best to work through the exercises. Then, come back to see how I did things. Have fun!

First! Create a class named Animal that has… a function named speak() that does nothing. That’s pretty straightforward.

class Animal {
  func speak() { }
}

That class doesn’t need an initializer, because it doesn’t have any stored properties. Just the one method. Next part - Create two Animal subclasses… Number one, a WildAnimal that… has an isPoisonous property, that is a Bool

class WildAnimal: Animal {
  let isPoisonous: Bool
}

This one does need an initializer to set that isPoisonous property!

  init(isPoisonous: Bool) {
    self.isPoisonous = isPoisonous
  }
}

Subclass number 2 should be a Pet class that has a stored property named name, that is a String

class Pet: Animal {
  let name: String
}

That one also needs an initializer to see its property.

  init(name: String) {
    self.name = name
  }

Pet also needs a play() method that prints out a message.

  func play() {
    print("Playtime! ... now naptime 💤")
  }

You could have done whatever you wanted with the parameters for that, but I just kept mine simple. And the final thing for pet, it should override speak() and print out a message

  override func speak() {
    print("Hi I'm \(name)! I am cute. Pet me!")
  }

I went ahead and used the name property in that message. Alright the last part of challenge 1! This was more open ended.

Create one subclass of your choice of WildAnimal or Pet. It should do at least one of the following:

  • override speak()
  • override play()
  • Add a new computed property
  • Add a new method

I’ll make a Cat class that says what all cats say.

class Cat: Pet {
  override func speak() {
    print("I can has Cheezeburger?")
  }
}

I can has cheezburger. Note the override keyword in front of that method!

On to challenge two! Create at least one instance of each class from the first challenge.

let animal = Animal()
let babyAragog = WildAnimal(isPoisonous: true)
let babySmaug = WildAnimal(isPoisonous: false)
let hamtaro = Pet(name: "Hamtaro")
let ozma = Cat(name: "Ozma")

I made two wild animals so one would be poisonous and one not. Next, Create an array that contains all of the instances.

let animals = [animal, babyAragog, babySmaug, hamtaro, ozma]

Swift is helping me out there, because it can figure out what the common parent class is for all of those instances! Now for the potentially longest part.

Write a function that takes an Animal and does something different depending on what subclass it is. This part is particularly vague, so you could have made it as complicated or simple as you liked.

I’ll write a function that prints out the pitch to give your family when you bring home some kind of animal and want to keep it.

func printElevatorPitch(forAnimal animal: Animal) {

}

The challenge suggested conditional downcasting, so, I’ll try that first with if let, checking for WildAnimals

  if let animal = animal as? WildAnimal {
  
  }

If it is a wild animal, I’ll print out something different depending on if it’s poisonous or not.

    print(animal.isPoisonous ? "It's only a little poisonous!" : "It's not even poisonous!")
    return
  }

I just used a ternary operator for that, but you could have use if or even a switch statement! Note that I also used return at the end to make sure the function stops running after the message is printed. Next, I’ll check for Pets.

  if let pet = animal as? Pet {

And inside there, since I have a Cat class that derives from Pet, I’ll switch things up and use a switch statement to pick the right printed message.

    switch pet {
    
    }

When you use a switch statement, and you want to see if you can downcast, you leave off the question mark.

    case let cat as Cat:
      print("It's a kitty named \(cat.name)! I've always wanted a kitty.")
      cat.speak()
      return

And then, because Pet only has the one subclass, I’ll use a default case to catch regular old Pets.

    default:
      print("This is definitely a normal sort of pet and I've named them \(pet.name).")
      pet.speak()
      pet.play()
      return
    }

I could leave it at that, but I’ll add one more print statement if none of those casts succeed. At that point, I could assume it’s of type Animal.

  print("It's Animal! You know, the Muppet?")
}

The very last bit of this challenge was to call the function with each of your instances. I’ll do that with forEach!

animals.forEach(printElevatorPitch(forAnimal:))

And there’s all of the possible messages in the console!