Currently the score and round increase as soon as we click on “Hit Me” button. But we would like them to increase when we click on “Ok” in the action box.
This can be handled using closures.
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: {
action in
self.startNewRound()
})
alert.addAction(action)
present(alert, animated: true, completion: nil)
For each button we have to specify a UIAlertAction object which has three parameters: the title of the alert message, sets the style of the alert message and the handler which tells the alert what should happen when a button is pressed. Before it was nil and so nothing was happening.
Now it starts the new round using a closure. The closure is a lot like an inline method with a parameter action.
Initial score 0 and round 1
Click on Hit Me doesn’t change the score and round now
Click on ok changes the score and round
Adding Extra Screens
Adding another screen to show the rules of the game when we click on the info button.
First, we create a new ViewController file. Click on File -> New -> File. Add the name AboutViewController and make it a subclass of UIViewController. Click on next and make sure BullsEye is selected. Then click on finish.
Next, add ViewContoller in main.storyboard. Add a button “close” and a TextView containing the instructions to this ViewController. Make sure the to uncheck the “editable” attribute of the TextView.
Next, we add the transition from first ViewController to the new ViewController using a Segue. Click on the info button + control and link it to the new ViewController. Select present modally.
Next, we need to link close to a method to dismiss the ViewController using an IBAction method close. In the method, we call another method to dismiss to dismiss the ViewController. Then go to main.storyboard file -> click on the new ViewController -> Go to the identity inspector (third tab) and set the class to AboutViewController. And link the button close to the method close.
Initial screen reappears on clicking the close button
Styling the app
Adding images to Assets.xcassets.
1x – old retina devices – 50×50 pixels
2x – high resolution retina displays – 100×100 pixels
3x – super high resolution retina HD screen – 150×150 pixels
To add a background image to the app, we add an ImageView in the first ViewController in the main.storyboard. And make the ImageView full screen. Then we set the image “Background” to this ImageView. Arrange the ImageView to go in the background.
Instead of “Hello World!” we will print different messages in the alert box based on how close we get to the random number.
If the difference is 0, we will print “Perfect!”. Else if the difference is less than 5, we will print “You almost had it!”. Else if the difference is less than 10, we will print “Pretty good!”. Else we will print “Not even close”.
Also, we will award an extra hundred points if the difference is 0 and an extra 50 points if the difference is 1.
The showAlert method looks like this –
let difference = abs(currentValue - targetValue)
var points = 100 - difference
let title: String
if difference == 0{
title = "Perfect!"
points += 100
}else if difference < 5 {
title = "You almost had it!"
if difference == 1{
points += 50
}
}else if difference < 10 {
title = "Pretty good..!"
}else {
title = "Not even close..."
}
score += points
let message: String = "You scored: \(points)"
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
Printing the value of the random number in the correct label
First creating an IBOutlet for the label to display the target random number and a global targetValue to hold the target random number.
@IBOutlet weak var targetLabel: UILabel!
var targetValue: Int = 0
Connecting this outlet to the label displaying 100 currently.
Since we need to update the targetValue for every round, we create a method startNewRound in which we generate a random value and assign it to targetValue. For swift 4.2+, we can generate random values using “Int.random(in: range)”. I have swift 4.1, therefore I used arc4random_uniform method.
In the updateLabels method, we convert the targetValue to String and assign it to the targetLabel.
Printing the value of the random number in the correct label
Calculating the difference between targetValue and sliderValue and displaying the difference in Alert box
To make sure the difference between currentValue and targetValue stays positive, we multiply the difference by -1.
Then we add the message to display the difference in the Alert box.
var difference: Int
difference = currentValue - targetValue
if difference < 0{
difference = difference * -1
}
let message: String = "The value of the slider is: \(currentValue)" + "\nThe value of the target is: \(targetValue)" + "\nThe value of the difference is: \(difference)"
Getting the value of slider and printing it in the Alert Box
Initialize a global variable currentValue of type Int and assign it the default value of 50.
Inside the sliderMoved method assign the slider.value.rounded() to the currentValue. Remember to cast slider.value.rounded() as we only need the integer values and not the decimal ones.
Copy the message inside the print statement in the sliderMoved method. Create another variable message inside showAlert() method of type string and assign the message to it. Replace slider.value in the message to currentValue.
Replace the old message in UIAlertController with message variable. Now run the app and change the slider position. Click Hit Me. We see the current value in the alert message.
Current Value of slider in Alert Message
Connecting Outlets
Right now we can access the slider only in one method. And we want to access its current value in another method or globally. This creates a need to have an instance variable of type UISlider. We can do that by using @IBOutlet like this
@IBOutlet weak var slider: UISlider!
Next open Main.storyboard -> control + click on slider -> click on New Referencing outlets and connect it to ViewController which pops up two options -> select slider
Now copy the code in sliderMoved to viewDidLoad. This makes sure that by default the current value of the slider is taken if the user hits the button “Hit Me!” without changing the slider value.
By default the slider’s value id 50. So now when we run the app and click on “Hit Me” , 50 is shown.