Chapters

Hide chapters

iOS Apprentice

Eighth Edition · iOS 13 · Swift 5.2 · Xcode 11

Getting Started with SwiftUI

Section 1: 8 chapters
Show chapters Hide chapters

My Locations

Section 4: 11 chapters
Show chapters Hide chapters

Store Search

Section 5: 13 chapters
Show chapters Hide chapters

18. Polish
Written by Eli Ganim

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

At this point, your game is fully playable. The gameplay rules are all implemented and the logic doesn’t seem to have any big flaws, but there’s still some room for improvement.

This chapter will cover the following:

  • Tweaks: Small UI tweaks to make the game look and function better.
  • The alert: Updating the alert view functionality so that the screen updates after the alert goes away.
  • Start over: Resetting the game to start afresh.

Tweaks

Obviously, the game is not very pretty yet — you will get to work on that soon. In the mean time, there are a few smaller tweaks you can make.

The alert title

Unless you already changed it, the title of the alert still says “Hello, World!” You could give it the name of the game, Bullseye, but there’s a better idea. What if you change the title depending on how well the player did?

@IBAction func showAlert() {
  let difference = abs(targetValue - currentValue)
  let points = 100 - difference
  score += points

  // add these lines
  let title: String
  if difference == 0 {
    title = "Perfect!"
  } else if difference < 5 {
    title = "You almost had it!"
  } else if difference < 10 {
    title = "Pretty good!"
  } else {
    title = "Not even close..."
  }

  let message = "You scored \(points) points"

  let alert = UIAlertController(title: title,  // change this
                              message: message, 
                       preferredStyle: .alert)

  let action = UIAlertAction(title: "OK", style: .default, 
                           handler: nil)
  alert.addAction(action)
  present(alert, animated: true, completion: nil)

  startNewRound()
}

Constant initialization

In the above code, did you notice that title was declared explicitly as being a String constant? And did you ask yourself why type inference wasn’t used there instead? Also, if title is a constant, how do we have code which sets its value in multiple places?

let title = ""
var title = ""
A constant needs to be initialized exhaustively
U kodhdeck jaelt ju ki ecofoihaleq ictaubgabezg

The alert with the new title
Lce ojogg qebp xye bux hutko

Bonus points

Exercise: Give players an additional 100 bonus points when they get a perfect score. This will encourage players to really try to place the bullseye right on the target. Otherwise, there isn’t much difference between 100 points for a perfect score and 98 or 95 points if you’re close but not quite there.

@IBAction func showAlert() {
  let difference = abs(targetValue - currentValue)
  var points = 100 - difference     // change let to var

  let title: String
  if difference == 0 {
    title = "Perfect!"
    points += 100                   // add this line
  } else if difference < 5 {
    title = "You almost had it!"
    if difference == 1 {            // add these lines
      points += 50					// add these lines
    }								// add these lines
  } else if difference < 10 {
    title = "Pretty good!"
  } else {
    title = "Not even close..."
  }
  score += points                   // move this line here from the top
  . . .
}
Raking in the points…
Zugivc ej tze puiqpv…

The alert

One annoying thing about the app is that as soon as you tap the Hit Me! button and the alert pops up, the slider immediately jumps back to its center position, the round number increments, and the target label already gets the new random number.

Asynchronous code execution

Maybe you’re wondering why this isn’t already happening? After all, in showAlert() you only call startNewRound() after you’ve shown the alert pop-up:

@IBAction func showAlert() {
  . . .
  let alert = UIAlertController(. . .)
  let action = UIAlertAction(. . .)
  alert.addAction(action)

  // Here you make the alert visible:
  present(alert, animated: true, completion: nil)

  // Here you start the new round:
  startNewRound()
}

Alert event handling

So, if your code execution can’t wait in showAlert() until the pop-up is dismissed, then how do you wait for it to close?

let action = UIAlertAction(title: "OK", style: .default, handler: nil)
@IBAction func showAlert() {
  . . .
  let alert = UIAlertController(. . .)

  let action = UIAlertAction(title: "OK", style: .default, 
                           handler: { _ in
                                         self.startNewRound()
                                    })

  alert.addAction(action)
  present(alert, animated: true, completion: nil)
}

Start over

No, you’re not going to throw away the source code and start this project all over! This part is about the game’s “Start Over” button. This button is supposed to reset the score and start over from the first round.

The new method

First, add a method to ViewController.swift that starts a new game. You should put it near startNewRound() because the two are conceptually related.

func startNewGame() {
  score = 0
  round = 0
  startNewRound()
}
@IBAction func startOver() {
  startNewGame()
}
@IBAction func startNewGame() {
  score = 0
  round = 0
  startNewRound()
}
override func viewDidLoad() {
  super.viewDidLoad()
  startNewGame()        // this line changed
}

Connect the outlet

Finally, you need to connect the Start Over button to the action method.

All the connections from View Controller to the other objects
Izx zru xunjuwxuoqj mmiy Ziog Zazzhaqzac pu kju owluf otpozcm

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now