# Playing a sound depending on the currently displayed flash card image

I've developed a fully working flash card app for kids. It has a UIImageView that cycles through 26 cards (abcs) via a gesture click and a music button that will play a sound for each image. Right now I have this 100% working, but the sound plays in an IF statement that has added an additional 400 lines of code.

How I load each card into the UIImageView from a gesture tap:

        // if the tapped view is a UIImageView then set it to imageview
if (gesture.view as? UIImageView) != nil {
if segControl.selectedSegmentIndex == 0 && segControl2.selectedSegmentIndex == 0 {
imageView.image = UIImage(named: "card\(number)")
number = number % 26 + 1
}
else if segControl.selectedSegmentIndex == 0 && segControl2.selectedSegmentIndex == 1 {
imageView.image = UIImage(named: "upper\(number)")
number = number % 26 + 1
}


Music button:

    if (imageView.image?.isEqual(UIImage(named: "card1")))! {
do { audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: aSound))
audioPlayer.play()
} catch {
print("Couldn't load sound file")
}
}
else if (imageView.image?.isEqual(UIImage(named: "card2")))! {
do { audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: bSound))
audioPlayer.play()
} catch {
print("Couldn't load sound file")
}
}
else if (imageView.image?.isEqual(UIImage(named: "card3")))! {
do { audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: cSound))
audioPlayer.play()
} catch {
print("Couldn't load sound file")
}
}


I know I could set a sound array with the sound files in it, but how would I tie it back to the card? I can't set a tag property on an asset image, can I?

I'm looking for a way to shorten the current code I have.

• What do aSound and bSound strings look like? – vacawama Jul 6 '19 at 16:53

You shouldn't determine the sound to play from the image displayed. Instead you should use the same piece of information to set both the image name and the sound path.

Create a property of your ViewController to keep track of the card number that is being displayed:

var displayedCard = 1


and set it whenever you assign a new image to the imageView:

// if the tapped view is a UIImageView then set it to imageview
if (gesture.view as? UIImageView) != nil {
if segControl.selectedSegmentIndex == 0 && segControl2.selectedSegmentIndex == 0 {
imageView.image = UIImage(named: "card\(number)")
displayedCard = number
number = number % 26 + 1
}
else if segControl.selectedSegmentIndex == 0 && segControl2.selectedSegmentIndex == 1 {
imageView.image = UIImage(named: "upper\(number)")
displayedCard = number
number = number % 26 + 1
}


Then use it to create the String you pass to URL(fileWithPath:):

// create the soundPath using displayedCard
let letter = String(UnicodeScalar(96 + displayedCard)!)
let soundPath = Bundle.main.path(forResource: "\(letter)Sound.m4a", ofType:nil)!

do { audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: soundPath))
audioPlayer.play()
} catch {
print("Couldn't load sound file")
}

• Sound strings look like this: let aSound = Bundle.main.path(forResource: "aSound.m4a", ofType:nil)! So when i set the displayedcard when loading it into the imageview, how would i then tell it that aSound belongs to card1, bSound to card2...etc? – Derek N Jul 6 '19 at 17:53
• See edit. letter will be a to z when displayedCard is 1 to 26. – vacawama Jul 6 '19 at 18:05
• WOW! Worked with literally no edit. Last question, i also have number flash cards 1-10, they are set as below: let num1Sound = Bundle.main.path(forResource: "num1.m4a", ofType:nil)! Would i just add the displayedcard like i did for the letter cards? And then create different constants for letter and soundPath? – Derek N Jul 6 '19 at 18:19
• That's easier because we don't have to map a number to a letter. let numSound = Bundle.main.path(forResource: "num\(displayedCard).m4a", ofType:nil)! – vacawama Jul 6 '19 at 18:22
• thank you, appreciate it – Derek N Jul 6 '19 at 18:30