I have sounds stored for different events within the struct that the user will be able to change, and was hoping i could send the function a string to select a song for a specific event.
my function call would look like this:
func playSound(audio: Audio, soundSelect: String = "startSound"){
if let path = Bundle.main.path(forResource: audio.\(soundSelect), ofType: audio.soundType){
do {
audioPlayer = try! AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
audioPlayer?.play()
}catch{
print("ERROR: Could not find and play the sound file!")
}
and my struct would look something like this:
struct Audio {
var startSound: String = "happyMusic"
var endSound: String = "sadMusic"
var soundType: String = "mp3"
}
as above i tried string interpolation which didn't seem to work I got the error
"Expected member name following '.'
What I expected was for "audio.\(soundSelect)"
to be read like "audio.startSound"
CodePudding user response:
You cannot build variable names at runtime because all variable names are evaluated at compile time.
But if you define the type of the parameter as a KeyPath
you are able to address different properties in the struct
func playSound(audio: Audio, soundSelect: KeyPath<Audio,String> = \.startSound) {
if let url = Bundle.main.url(forResource: audio[keyPath: soundSelect], withExtension: audio.soundType) {
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch {
print("ERROR: Could not find and play the sound file!", error)
}
}
}
Notes:
If you implement a
do - catch
block handle (removing the question mark intry?
) andprint
the error rather than just a meaningless string literal.Bundle
provides an URL related API which avoids the extraURL(fileURLWithPath
call
A still swiftier syntax is to make the function throw
and hand over the error(s) to the caller
func playSound(audio: Audio, soundSelect: KeyPath<Audio,String> = \.startSound) throws {
if let url = Bundle.main.url(forResource: audio[keyPath: soundSelect], withExtension: audio.soundType) {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} else {
throw URLError(.badURL)
}
}