The following lines show the code for the Animal
base class in Swift. The class header doesn't specify a base class, so this class will become our base class for the other classes. The code file for the sample is included in the swift_3_oop_chapter_04_01
folder:
open class Animal { open static var numberOfLegs: Int { get { return 0; } } open static var averageNumberOfChildren: Int { get { return 0; } } open static var abilityToFly: Bool { get { return false; } } open var age: Int init(age : Int) { self.age = age print("Animal created") } open static func printALeg() { preconditionFailure("The pringALeg method must be overriden") } open func printLegs() { for _ in 0..<type(of: self).numberOfLegs { type(of: self).printALeg() } print(String()) } open static func printAChild() { preconditionFailure("The printChild method must be overriden") } open func printChildren() { for _ in 0..<type(of: self).averageNumberOfChildren { type(of: self).printAChild() } print(String()) } open func printAge() { print("I am (age) years old.") } }
The preceding class declares two read-only type computed properties and both return 0
as their value: numberOfLegs
and averageNumberOfChildren
. In addition, the class declares another read-only type computed property that returns false as its value: abilityToFly
. We will be able to return different values for these properties in the different subclasses of Animal
.
The initializer requires an age
value to create an instance of the class and prints a message indicating that an animal is created. The class declares an age
stored instance property. It defines the following three instance methods:
printAge
: This displays the age based on the age
valueprintALeg
: This uses preconditionFailure
to indicate that each subclass must override this type method with a specific implementation that prints a single leg for the animalprintAChild
: This uses preconditionFailure
to indicate that each subclass must override this type method with a specific implementation that prints a single child for the animalIn addition, the class declares the following two type methods:
printLegs
: This calls the printALeg
method the number of times specified in the numberOfLegs
type property. The method uses the type
function with self
as the value for the of
argument to retrieve the runtime type as a value and access the type property for the specific type that we used to create the instance.printChildren
: This calls the printAChild
method the number of times specified in the averageNumberOfChildren
type property. As it happened in the pringLegs
property, the code uses the type
function with self
as the value for the of
argument to access the necessary type property.If we execute the following line in the Playground after declaring the Animal
class, Swift will generate a fatal error and indicate that the printAChild
type method must be overridden, as shown in the subsequent screenshot. We will see similar error messages in the Swift REPL and in the Swift Sandbox. The code file for the sample is included in the swift_3_oop_chapter_04_02
folder:
Animal.printAChild()
We have to add additional functions to allow us to compare the ages of different Animal
instances using operators. We will add the necessary code to perform this task later.
The following lines show the code for the Mammal
class that inherits from Animal
. Note the class
keyword followed by the class name Mammal
, a colon (:
), and Animal
, which is the superclass from which it inherits, in the class definition. The code file for the sample is included in the swift_3_oop_chapter_04_03
folder:
open class Mammal: Animal {
open var isPregnant: Bool = false
private func initialize(isPregnant: Bool) {
self.isPregnant = isPregnant
print("Mammal created")
}
override init(age: Int) {
super.init(age: age)
initialize(isPregnant: false)
}
init(age: Int, isPregnant: Bool) {
super.init(age: age)
initialize(isPregnant: isPregnant)
}
}
The Mammal
class inherits the members from the previously declared Animal
class and adds a new Bool
stored property initialized with the default false
value. Note that this class declares two designated initializers. One of the initializers requires an age
value to create an instance of the class, as it happened with the Animal
initializer. The other initializer requires the age
and isPregnant
values. If we create an instance of this class with just one age
argument, Swift will use the first initializer. If we create an instance of this class with two arguments--an Int
value for age
and a Bool
value for isPregnant
--Swift will use the second initializer. Thus, we have overloaded the initializer and provided two different initializers. Of course, we could also take advantage of optional parameters. However, in this case, we want to overload initializers.
The two initializers use the super
keyword to call the inherited init
method from the base class or superclass, that is, the init
method defined in the Animal
class. Once the superclass's initializer finishes its execution, each initializer calls the initialize
private method that initializes the isPregnant
stored property with the value received as an argument or the default false
value in case it isn't specified.
One of the initializers uses the override
keyword to override the initializer with the same declaration that is included in the superclass. We already had an initializer with an age
argument of type Int
in the Animal
superclass. The other initializer doesn't require the override keyword because there is no initializer declared in the Animal
superclass with the same arguments.
The following lines create an instance of the Mammal
class in the Playground using the designated initializer that just requires an age
argument. The code file for the sample is included in the swift_3_oop_chapter_04_03
folder:
var bat = Mammal(age: 3) bat.printAge() print(bat.isPregnant)
The following lines show the results of the preceding lines. When the superclass initializer is executed, it prints Animal created
, and after this happens, the initializer defined in the Mammal
class prints Mammal created
. The call to the printAge
method defined in the Animal
superclass prints the actual value of the age property in this instance of the Mammal
class. Finally, a line prints the value of the isPregnant
property that was initialized with false
because we didn't specify a value for it:
Animal created Mammal created I am 3 years old. false
The following lines create another instance of the Mammal
class in the Playground using the initializer that requires two arguments: age
and isPregnant
. The code file for the sample is included in the swift_3_oop_chapter_04_03
folder:
var cat = Mammal(age: 6, isPregnant: true) cat.printAge() print(cat.isPregnant)
The following lines show the results of the preceding lines. The last line prints the value of the isPregnant
property that was initialized with true
in the initializer defined in the Mammal
class:
Animal created Mammal created I am 6 years old. true
The following screenshot shows the results of executing the preceding code in the Playground:
18.188.228.180