Each superhero has a running speed score that determines how fast he will move when running; therefore, we will add a public runningSpeedScore
property. We will change the initializer code to set an initial value for the new property. However, this new property has some specific requirements.
Whenever the running speed score is about to change, it will be necessary to trigger a few actions. In addition, we have to trigger other actions after the value for this property changes. We might consider adding code to a setter method combined with a related property, run code before we set the new value to the related property, and then run code after we set the new value. However, Swift allows us to take advantage of property observers that make it easier to run the code before and after the running speed score changes.
We can define a public runningSpeedScore
property with both a willSet
and didSet
methods. After we create an instance of the new version of the SuperHero
class and initialize the new property with its initial value, the code in the willSet
method will be executed when we assign a new value to the property and before Swift sets the new value to the property. Thus, at the time the willSet
method executes the code, the property still has the previous value, and we can access the new value that will be set by checking the value of the newValue
implicit parameter.
Then, when Swift changes the value of the property, the didSet
method will be executed. Thus, at the time the didSet
method executes the code, the property has the new value.
The following lines show the code that defines the new public runningSpeedScore
property with the property observers and the new code for the initializer. Note that the code for the rest of the class isn't included in order to avoid repeating the previous code. The code file for the sample is included in the swift_3_oop_chapter_03_09
folder:
public var runningSpeedScore: Int { willSet { print("The current value for running speed score is:(runningSpeedScore)") print("I will set the new value for running speed score to: (newValue)") } didSet { print("I have set the new value for running speed score to: (runningSpeedScore)") } } init(name: String, birthYear: Int, sneakers: String, runningSpeedScore: Int) { self.name = name self.birthYear = birthYear self.runningSpeedScore = runningSpeedScore self.sneakers = sneakers }
The willSet
method prints the current value of runningSpeedScore
and the new value that will be set to this property and received in the newValue
implicit parameter. The didSet
method prints the new value that is set to the runningSpeedScore
property.
The initializer for the class added a new argument that provides an initial value to the new runningSpeedScore
property. The next lines create an instance of the SuperHero
class and assign a value to the runningSpeedScore
property. Note that both the willSet
and didSet
methods were executed only once because the code didn't run when we initialized the value of the property. Enter the lines after the code that creates the new version of the SuperHero
class. The code file for the sample is included in the swift_3_oop_chapter_03_09
folder:
var superBoy = SuperHero(name: "Super-Boy", birthYear: 2008, sneakers: "Running with Swift 3", runningSpeedScore: 5) print(superBoy.sneakers) superBoy.runningSpeedScore = 7
The Playground displays a message indicating the current value of the property before the new value that is set, that will be set, and finally, that was set, as shown in the next screenshot:
We can use the didSet
method to keep the value of a property in a valid range. For example, we can define the runningSpeedScore
property with a didSet
method, which transforms the values lower than 0
to 0
and values higher than 50
to 50
. The following code will do the job. We have to replace the previous code, which declared the runningSpeedScore
property, with the new code. The code file for the sample is included in the swift_3_oop_chapter_03_10
folder:
public var runningSpeedScore: Int { didSet { if (runningSpeedScore < 0) { runningSpeedScore = 0 } else if (runningSpeedScore > 50) { runningSpeedScore = 50 } } }
The next lines create an instance of the SuperHero
class and try to assign different values to the runningSpeedScore
property. Enter the lines after the code that creates the new version of the SuperHero
class:
var superBoy = SuperHero(name: "Super-Boy", birthYear: 2008, sneakers: "Running with Swift 3", runningSpeedScore: 5) print(superBoy.runningSpeedScore) superBoy.runningSpeedScore = -5 print(superBoy.runningSpeedScore) superBoy.runningSpeedScore = 200 print(superBoy.runningSpeedScore) superBoy.runningSpeedScore = 6 print(superBoy.runningSpeedScore)
After we specified -5
as the desired value of the runningSpeedScore
property, we printed its actual value, and the result was 0. After we specified 200
, the actual printed value was 50. Finally, after we specified 6
, the actual printed value was 6, as shown in the next screenshot. The code in the didSet
method did its job; we can control all the values accepted for the property. Note that the didSet
method doesn't execute one more time when we set the new value for the property within the didSet
method.
The code file for the sample is included in the swift_3_oop_chapter_03_10
folder:
We can use the didSet
method when we want to validate the values accepted for a property after it is initialized. Remember that the didSet
method isn't executed when the property is initialized. Thus, if we execute the following lines, the printed value will be 135
, and the property will be initialized with an invalid value. Enter the lines after the code that creates the new version of the SuperHero
class. The code file for the sample is included in the swift_3_oop_chapter_03_11
folder:
var superFlash = SuperHero(name: "Flash", birthYear: 1972, sneakers: "Flash running", runningSpeedScore: 135) print(superFlash.runningSpeedScore)
3.15.229.161