Day 20 - 100 Days of Swift

5 minute read

Project 2 (part 2)

Day 20 is the second half of the “pick a flag” game. You update the askQuestion method to pick random flags and an answer. You add actions from the three buttons and build out the function that they run when you tap on them. And you display an alert to the user after each turn alerting them of their score.

First, you shuffle the array so that the three flags presented in askQuestion are different each time:

1
countries.shuffle()

Then you add a variable to hold the correct answer:

1
var correctAnswer = 0

Then you pick which flag will be the right answer for this round:

1
correctAnswer = Int.random(in: 0...2)

And then set the title to the country that was picked:

1
title = countries[correctAnswer].uppercased()

This leaves the askQuestion method looking like this:

1
2
3
4
5
6
7
8
9
10
11
func askQuestion() {
    countries.shuffle()

    button1.setImage(UIImage(named: countries[0]), for: .normal)
    button2.setImage(UIImage(named: countries[1]), for: .normal)
    button3.setImage(UIImage(named: countries[2]), for: .normal)

    correctAnswer = Int.random(in: 0...2)

    title = countries[correctAnswer].uppercased()
}

Next you connect the three buttons to an action called pickFlag:

Screenshot of adding actions.

You add a tag to each of the flags so that they can be identified:

Screenshot of setting tags.

Next, you add some code check if the user picked the right flag:

1
2
3
4
5
6
7
8
9
var title: String

if sender.tag == correctAnswer {
    title = "Correct"
    score += 1
} else {
    title = "Wrong"
    score -= 1
}

And some code to present an alert to the user:

1
2
3
4
5
6
7
8
let ac = UIAlertController(title: title,
                           message: "Your score is \(score).",
                           preferredStyle: .alert)
let action = UIAlertAction(title: "Continue",
                           style: .default,
                           handler: askQuestion)
ac.addAction(action)
present(ac, animated: true)

This causes an error, because askQuestion is not written to accept a UIAlertAction, which is what the closure is looking for. So you make a small tweak to that function definition to allow for that:

1
func askQuestion(action: UIAlertAction! = nil) {

Because we aren’t actually using the alert action in the function, it doesn’t matter if it is implicitly unwrapped and nil (which it should only be the first time it is called in viewDidLoad), but this allows us to get around the compiler warnings.

Screenshot of working app.

The app runs at this point, and operates like it is supposed to! But I decided to play around and see if I could improve things a little bit. The first thing I did was to add the three buttons to an outlet collection, instead of individually referencing each one:

1
2
3
4
@IBOutlet var buttons: [UIButton]!
//@IBOutlet var button1: UIButton!
//@IBOutlet var button2: UIButton!
//@IBOutlet var button3: UIButton!

This means I can set the image for each one with a for loop:

1
2
3
for (index, button) in buttons.enumerated() {
    button.setImage(UIImage(named: countries[index]), for: .normal)
}

I can set up the border for each one the same way. I also set the tags programmatically, so that I don’t have set each one individually in the storyboard:

1
2
3
4
for (index, button) in buttons.enumerated() {
    button.addBorder()
    button.tag = index
}

Neither of these is really that much of an improvement on their own, other than they are slightly less repetitive. But it means my app is set up to have a variable number of flag buttons, with only one more small change. The correct answer needs to be set to a random int based on the count of buttons, instead of being tied to 0, 1, or 2:

1
correctAnswer = Int.random(in: 0..<buttons.count)

Then all I need to do to add another button is to option+click and drag from the bottom button to copy it, constrain it to stay in place, and add it to the outlet collection.

Screenshot of working app.

You can find my version of the project at the end of Day 20 on Github here.

Reflections

Woot woot! Day 20! That means I’m one fifth of the way through this! It is still a bit of a slog, but it is definitely getting easier as time goes on and I get into the habit of writing one of these blog posts every day. In the past I never ended up writing that much because I was afraid it would be too small, or insignificant, or not good enough. So I would spend a long time on one post, and get exhausted from the amount of work it took, and stop writing for a while. Doing 100 Days of Swift has helped me get over that. There isn’t enough time to agonize over each post because there is always another one coming. I’m not saying I half-ass these, or that I think I will write a post a day for the rest of my life, but this process has definitely helped me get over that mental block.