Treating instances of a protocol type as a different subclass

Now, we will take advantage of the capability that Swift offers us to extend an existing class to add specific members. In this case, we will add an instance method to the previously defined AngryCat class. The following lines add the doSomethingWith method to the existing AngryCat class. The code file for the sample is included in the swift_3_oop_chapter_05_11 folder:

    public extension AngryCat { 
      public func doSomethingWith(cat: AngryCat) { 
        if let angryCatAlien = cat as? AngryCatAlien { 
          angryCatAlien.appear() 
        } else if let angryCatKnight = cat as? AngryCatKnight { 
          angryCatKnight.unsheathSword() 
        } else if let angryCatWizard = cat as? AngryCatWizard { 
          print("My spell power is (angryCatWizard.spellPower)") 
        } else { 
          print("This AngryCat doesn't have cool skills.") 
        } 
      } 
    } 

Tip

Take into account that extensions cannot use open as their default access. When we want them to be accessible outside the module that defines them, we must use the public access modifier.

The doSomethingWith method receives an AngryCat instance (cat) and uses the conditional type casting operator (as?) to return an optional value of the type that it tries to cast cat to. In case cat is an instance of AngryCatAlien or of any potential subclass of AngryCatAlien, the first type cast succeeds and the code calls the appear method for the cat type cast to an AngryCatAlien instance, which is saved in the angryCatAlien reference constant, as follows:

    if let angryCatAlien = cat as? AngryCatAlien { 
      angryCatAlien.appear() 

In case the conditional type cast to AngryCatAlien fails, the code uses the conditional type casting operator (as?) and tries to cast cat to AngryCatKnight. In case cat is an instance of AngryCatKnight or an instance of any potential subclass of AngryCatKnight, the conditional type cast succeeds, and the code calls the unsheathSword method for the cat type cast to an AngryCatKnight instance, which is saved in the angryCatKnight reference constant:

    } else if let angryCatKnight = cat as? AngryCatKnight { 
      angryCatKnight.unsheathSword() 

In case the conditional type cast to AngryCatKnight fails, the code uses the conditional type casting operator (as?) and tries to cast cat to AngryCatWizard. In case cat is an instance of AngryCatWizard or of any potential subclass of AngryCatWizard, the conditional type cast succeeds, and the code prints a message indicating the spellPower value for the cat type cast to an AngryCatWizard instance, which is saved in the angryCatWizard reference constant, as follows:

    } else if let angryCatWizard = cat as? AngryCatWizard { 
      print("My spell power is (angryCatWizard.spellPower)") 

Finally, if the last conditional type cast to AngryCatKnight fails, it means that the cat instance just belongs to AngryCat, so the code prints a message indicating that AngryCat doesn't have cool skills.

Tip

Whenever type casting fails, we must use the conditional form (as?) of the type cast operator.

Now, we will take advantage of the doSomethingWith instance method added to the AngryCat class and call it in instances of AngryCat and its subclasses, which we created before we declared the extension. We will call the doSomethingWith method for the AngryCat instance named garfield and use it the following arguments:

  • misterAlien: This is an instance of the AngryCatAlien class
  • camelot: This is an instance of the AngryCatKnight class
  • gandalf: This is an instance of the AngryCatWizard class
  • garfield: This is an instance of the AngryCat class

The following four lines call the doSomethingWith method in the Playground with the previously enumerated arguments. The code file for the sample is included in the swift_3_oop_chapter_05_11 folder:

    garfield.doSomethingWith(cat: misterAlien) 
    garfield.doSomethingWith(cat: camelot) 
    garfield.doSomethingWith(cat: gandalf) 
    garfield.doSomethingWith(cat: garfield) 

The next lines show the output generated in the Playground. Each call triggers a different type cast and calls a method of the type cast instance:

    I'm Mr. Alien and you can see my 3 eyes. 
    Sir Camelot unsheaths his sword. 
    Sword power: 100. Sword weight: 30. 
    My spell power is 100 
    This AngryCat doesn't have cool skills. 

The following screenshot shows that the execution of the four methods generates the doSomethingWith method to execute code in each usage of the conditional type cast operator. Note the values displayed on the right-hand side of each line included within the curly braces after each conditional type cast. The lines that call the methods just display the type cast instance types, AngryCatAlien and AngryCatKnight, and the lines that call the print method display the generated output on the right-hand side:

Treating instances of a protocol type as a different subclass

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.3.72