Follow along at https://www.hackingwithswift.com/100/20.
This day covers the second part of Project 2: Guess the Flag
in Hacking with Swift.
I have a separate repository where I've been creating projects alongside the material in the book. And you can find Project 2 here. However, this day focused specifically on a number of topics:
- Presenting random flags to guess
- Creating an
IBAction
for flags
One of the primary challenges we face is figuring out how to choose 3 unique flags at random to present to the user. With our flag choices set as an array, we could use randomElement
to pick out a name — but then we still have to make sure each pick is unique. The solution for this is only a bit more intricate: we can first shuffle the array, and then just take the first three elements:
let flagChoices = Array(flagNames.shuffled()[..<3])
And to ensure that our answer has a random position:
let correctFlagChoice = flagChoices.randomElement()
Similar to creating @IBOutlet
connections from Interface Builder to code, we can also create @IBAction
connections — bindings between interface events and the functions that handle them.
@IBAction func buttonTapped(_ sender: UIButton) {
}
Unlike outlets, however, we don't want a different handle for each button — we want to be able to have the same function handle taps on all of our buttons. Fortunately, Xcode allows us to create connections from several different elements to a single @IBAction
handler. In retrospect, of course it would — but it's one of those things that feels delightful the first time you learn about it 🙂.
Anyways, because these functions are called with a sender
— the interface element that was the target of the event — we can take advantage of the sender's tag
attribute to infer which specific flag was tapped. Here was the original code that I came up with:
@IBAction func buttonTapped(_ sender: UIButton) {
let flagKeyChosen = flagChoiceKeys[sender.tag]
if flagKeyChosen == correctFlagKey {
handleChoice(wasCorrect: true)
} else {
handleChoice(wasCorrect: false)
}
}
Looking back, I have more thoughts about how I'd structure some of the data here, which I'll try to address in the next day's wrap-up. (It's always nice to be able to look back at old code and know better.) For now, though, this covers some important concepts related to interface events and action handling — which Storyboards, divisive though they may be, allow us to connect in some very useful ways 🙌.