What I was trying to do
I wanted to implement alarm sounds and BGM that could be changed from a settings screen!
The fix
Use Bundle.main.url.
Something like this works fine:
@State private var alarmSoundName: String = "bell"
var endAlarm: URL {
return Bundle.main.url(forResource: alarmSoundName, withExtension: "mp3")!
}
func playAlarm() {
do {
alarmPlayer = try AVAudioPlayer(contentsOf: endAlarm)
alarmPlayer?.play()
} catch {
print("Sound playback failed.")
}
}
One thing to note: with this approach, you can't reach files that live inside Assets.xcassets.
I just created a folder named something like Sounds and put everything there instead.
What I tried first
Initially, I tried following the same pattern as pulling images — storing the mp3 in Assets.xcassets and loading it with NSDataAsset.
Trying to implement it like the code below didn't work. ⚠️
@State private var alarmSound: String = "bell"
let endAlarm = NSDataAsset(name: alarmSound)!.data
It turns out that in Swift, you can't use a variable when dynamically constructing an NSDataAsset.
Since NSDataAsset has to be initialized at compile time, you can't build it dynamically using a variable.
So instead I used the Bundle.main.url approach, which worked fine with State.