A class can inherit (inherit) and has a class method, property, and other features. When a class inherits other classes, the inherited class is called subclass, And the inherited class is called superclass (or parent class, superclass ). In swift, inheritance is a basic feature that distinguishes a class from other types.
In swift, classes can call methods, attributes, and subscripts of superclasses, and can overwrite these methods, the behavior of attributes and ancillary scripts to optimize or modify them. Swift checks whether your override definition has a matching definition in the superclass to ensure that your rewrite behavior is correct.
The property observer can be added to the inherited attributes of the class. As a result, when the property value changes, the class will be notified. An Attribute observer can be added for whatever attribute, whether it was originally defined as a stored property or a compute property ).
Define a base class)
Classes that do not inherit from other classes are called base calss ).
Note:
Classes in swift are not inherited from a general base class. If you do not specify a superclass for your defined class, the class automatically becomes the base class.
The following example defines a base class named vehicle. This base class declares two attributes that are common to all vehicles (numberofwheels and maxpassengers ). These attributes are used in the description method. This method returns a string type, describing the vehicle features:
class Vehicle { var numberOfWheels: Int var maxPassengers: Int func description() -> String { return "\(numberOfWheels) wheels; up to \(maxPassengers)passengers" } init() { numberOfWheels = 0 maxPassengers = 1 }}
The vehicle class defines the constructor (initializer) to set the attribute value. The constructor will introduce the constructor In the constructor section. Here we will introduce the constructor to explain how the inherited attributes of sub-classes are modified.
The constructor is used to create a new instance of a certain type. Although the constructor is not a method, the two are very similar in syntax. The constructor prepares a new instance for use and ensures that all attributes of the Instance have valid initialization values.
The simplest form of constructor is like an instance method without the number of workers, using initkeyword:
Init () {// run the constructor}
Assume that you want to create a new instance of the vehicle class and use the constructor syntax to call the initialization tool above, that is, the class name is followed by an empty parentheses:
let someVehicle = Vehicle()
The vehicle class constructor sets initialization attribute values for a random vehicle (numberofwheels = 0 and maxpassengers = 1 ).
The vehicle class defines the common characteristics of vehicles, but it is not very useful. To make it more useful, you need to further refine it to describe more detailed vehicles.
Subclassing)
Subclassing refers to creating a new class based on an existing class. Subclass inherits the features of a superclass and can be optimized or changed. You can also add new features to sub-classes.
To specify the superclass of a class, write the superclass name behind the subclass name and separate it with a colon:
Class someclass: somesuperclass {// class definition}
In the next example, we will define a more detailed vehicle class called Bicycle. This new class is created based on the vehicle class. Therefore, you need to put the vehicle class behind the bicycle class and separate them with colons.
We can read this:
"Define a new class called bicycle, which inherits the features of vehicle ";
class Bicycle: Vehicle { init() { super.init() numberOfWheels = 2 }}
A bicycle is a subclass of vehicle, and a vehicle is a superclass of a bicycle. The new bicycle class proactively obtains the features of the vehicle class, such as the maxpassengers and numberofwheels attributes. You can customize these features in the subclass or add new features to better describe the bicycle class.
The bicycle class defines a constructor to set its custom features (a bicycle has only two wheels ). The bicycle constructor calls the constructor super. INIT () of its parent vehicle class to ensure that the vehicle class has initialized them before the bicycle class tries to modify the inherited attributes.
Note:
Unlike objective-C, in swift, the initiators do not inherit by default. For details, see the inheritance and rewriting of the initiaters.
The default value of maxpassengers in the vehicle class is correct for bicycles, so it is not changed in the bicycle constructor. The original numberofwheels value is incorrect for the bicycle, so it is changed to 2 in the initialization tool.
A bicycle not only inherits the attributes of a vehicle, but also its methods. Suppose you have created a bicycle class instance, you can call the description method inherited by it, and you can see that the output property value has changed:
let bicycle = Bicycle()println("Bicycle:\(bicycle.description())")// Bicycle: 2 wheels; up to 1 passengers
Subclass can be inherited by other classes:
class Tandem: Bicycle { init() { super.init() maxPassengers = 2 }}
In the preceding example, a subclass of bicycle is created: Double bicycle (TANDEM ). Tandem inherits two attributes from bicycle, which are inherited from vehicle. Tandem does not change the number of wheels because it is still a bicycle and has two wheels. But it needs to change the value of maxpassengers, because a two-person bicycle can ride two people.
Note:
The subclass only agrees to modify the attributes of variables inherited from the superclass, rather than the inherited constant attributes.
Create an instance of the tandem class and print its description to see that its attributes have been updated:
let tandem = Tandem()println("Tandem:\(tandem.description())")// Tandem: 2 wheels; up to 2 passengers
Note that the tandem class also inherits the description method. The instance method of a class is inherited by all sub-classes of the class.
Overriding)
Subclasses can be inherited instance methods, class methods, instance properties, or subscripts) provides customized implementation (implementation ). We call this behavior overriding ).
To rewrite a feature, you must add overridekeyword before the definition rewriting. By doing so, you indicate that you want to provide an rewrite version number, rather than mistakenly providing the same definition. Unexpected rewriting may lead to unpredictable errors. Whatever overridekeyword is missing, it will be diagnosed as an error during compilation.
Overridekeyword reminds the swift compiler to check whether the super class (or one of the parent classes) of this class has a declaration that matches the rewrite version number. This check ensures that your rewrite definition is correct.
Methods, attributes, and scripts of the superclass
When you override a superclass method, attribute, or ancillary script in a subclass, it is helpful to use an existing superclass implementation in your rewrite version number. For example, you can optimize existing implementations or store a modified value in an inherited variable.
In a proper place, you can use the super prefix to explain the methods, attributes, or ancillary scripts for asking the superclass version number:
In the method somemethod rewriting implementation, super. somemethod () can be used to call the somemethod method of the superclass version number.
In the rewriting implementation of the getter or setter attribute of someproperty, you can use super. someproperty to explain the someproperty attribute of the super class version number.
In the rewrite Implementation of the ancillary script, you can use super [someindex] to explain the similar ancillary script in the superclass version number.
Rewrite Method
In subclass, You can override the inherited instance methods or class methods to provide a customized or alternative method implementation.
The following example defines a new subclass of vehicle called car, which overwrites the description method inherited from the vehicle class:
class Car: Vehicle { var speed: Double = 0.0 init() { super.init() maxPassengers = 5 numberOfWheels = 4 } override func description() -> String { return super.description() + "; " + "traveling at \(speed) mph" }}
Car declares a new storage-type attribute speed, which belongs to the double type. The default value is 0.0, indicating that "the speed is 0 miles per hour ". The car has its own initialization device. It sets the maximum number of passengers to 5 and the number of wheels to 4.
Car overwrites the inherited description method. Its declaration is consistent with the description method in vehicle. overridekeyword is added before the declaration.
The description method in car is not completely defined by itself, but uses the description method in the super class vehicle through Super. description, and then append some additional information, such as the current speed of the car.
Suppose you create a new car instance and print the description method output, you will find that the description information has changed:
let car = Car()println("Car:\(car.description())")// Car: 4 wheels; up to 5 passengers;traveling at 0.0 mph
Rewrite attributes
You can override inherited instance attributes or class attributes, provide custom getter and setter, or add the attribute observer to observe when the attribute values are changed.
Getters and setters of the override attribute
You can provide custom getter (or setter) to override random inherited attributes, whether they are stored or computed. The subclass does not know whether the inherited attributes are stored or computed. It only knows that the inherited attributes have a name and type. When you override an attribute, you must write its name and type. In this way, the compiler can check that the attributes you overwrite match those of the same name in the super class.
You can rewrite an inherited read-only attribute to a read-write attribute. You only need to provide getter and setter in the attributes of the rewrite version number. However, you cannot rewrite an inherited read/write attribute to a read-only attribute.
Note:
If you provide setter in the rewrite attribute, you must also provide getter. If you do not want to change the inherited attribute value in the getter of the rewrite version number, you can directly return Super. someproperty to return the inherited value. As shown in the following example of speedlimitedcar.
The following example defines a new class called speedlimitedcar, which is a subclass of car. Speedlimitedcar indicates a vehicle with a speed limiting device installed, and its shortest speed can only reach 40 mph. You can achieve this speed limit by rewriting the inherited speed attribute:
class SpeedLimitedCar: Car { override var speed: Double { get { return super.speed } set { super.speed = min(newValue, 40.0) } }}
When you set the speed attribute of a speedlimitedcar instance, the implementation of the property setter checks the size of the new value and the limit value of 40mph, it sets the speed of the superclass to the smaller value in newvalue and 40.0. Which of the two values is smaller depends on the min function, which is a global function in the swift standard library. The min function receives two or more other numbers and returns the smallest of them.
Suppose you try to set the speed attribute of the speedlimitedcar instance to a value greater than 40 mph, and then print the output of the description function, you will find that the speed is limited to 40 mph:
let limitedCar = SpeedLimitedCar()limitedCar.speed = 60.0println("SpeedLimitedCar:\(limitedCar.description())")// SpeedLimitedCar: 4 wheels; up to 5passengers; traveling at 40.0 mph
Property observer)
You can add an attribute observer to an inherited attribute in the attribute rewriting. In this way, when the inherited attribute value changes, you will be notified, no matter how the property was originally implemented. For more information about the attribute observer, see attribute observer.
Note:
You cannot add an attribute observer to an inherited constant storage attribute or an inherited read-only computing attribute. The values of these attributes cannot be set. Therefore, it is inappropriate to provide them with willset or didset implementations. In addition, you cannot provide the rewritten setter and the rewritten attribute Observer at the same time. Suppose you want to observe the changes in the property value, and you have provided custom setter for that property, then you can observe whatever value changes in setter.
The following example defines a new class named automaticcar, which is a subclass of car. Automaticcar indicates that the vehicle is automatically blocked. It can automatically select the appropriate gear according to the current speed. Automaticcar also provides a custom description method to output the current gear.
class AutomaticCar: Car { var gear = 1 override var speed: Double { didSet { gear = Int(speed / 10.0) + 1 } } override func description() -> String { return super.description() + " in gear \(gear)" }}
When you set the speed attribute of automaticcar, The didset observer of the attribute automatically sets the gear attribute and selects a proper gear for the new speed. In details, the attribute observer divides the new speed value by 10, obtains the nearest integer downward, and Adds 1 to get the gear value of the gear. For example, when the speed is 10.0, the block is 1; when the speed is 35.0, the block is 4:
let automatic = AutomaticCar()automatic.speed = 35.0println("AutomaticCar:\(automatic.description())")// AutomaticCar: 4 wheels; up to 5passengers; traveling at 35.0 mph in gear 4
Prevent Rewriting
You can mark methods, properties, or ancillary scripts as final to prevent them from being overwritten. You only need to add the @ final feature before declaring keyword. (For example, @ final var, @ final func, @ final class func, and @ finalsubscript)
If you overwrite the final method, attribute, or ancillary script, an error is reported during compilation. In the extension, the methods you add to the class, attributes or ancillary scripts can also be marked as final in the extension definition.
You can add the @ final feature (@ final class) before keywordclass to mark the entire class as final, which cannot be inherited; otherwise, a compilation error is reported.