Reputation: 673
I'm playing a sound in a SwiftUI view, and I'd like to set a value in an @EnvironmentObject when the sound completes.
So, I declare protocol compliance, and my completion handler is duly called. BUT, I can't set a value in my @EnvironmentObject, because the completion handler doesn't live in the SwiftUI view hierarchy.
My first thought was to pass the settings: EnvironmenObject to MyPlayerDelegate, but I was foiled because settings is an instance variable.
Any ideas?
Here's the code:
import SwiftUI
import AVFoundation
var audioPlayer: AVAudioPlayer!
import MediaPlayer
import AVKit
protocol PlayerDelegate: AnyObject {
func soundFinished(_ sender: Any)
}
struct MeditationView: View {
@EnvironmentObject var settings: Settings
var myPlayerDelegate = MyPlayerDelegate()
var body: some View {
ZStack {
settings.rainbowColour
.animation(.easeInOut(duration: 1))
VStack {
meditationImage(colour: settings.rainbowColour)
.resizable()
.opacity(settings.showRainbow ? 0 : 1)
.scaledToFit()
.onAppear() {
if let audioFileURL =
Bundle.main.url(forResource: settings.meditation,
withExtension: "mp3")
{
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
guard let player = audioPlayer else {print("Unable to find " + settings.meditation); return}
player.prepareToPlay()
player.delegate = myPlayerDelegate
player.play()
} catch let error {
print("Unable to play the meditation sound" + settings.meditation)
print(error.localizedDescription)
}
} else {
print("Unable to load sound: " + settings.meditation)
}
} // .onAppear
.onTapGesture {
if let player = audioPlayer {
player.pause()
}
settings.showRainbow = true;
}
Text("Tap to return to the rainbow")
}
} // ZStack
}
class MyPlayerDelegate : NSObject, ObservableObject, AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
// settings.showRainbow = true;
}
}
}
Upvotes: 0
Views: 100
Reputation: 673
Figured it out.
The EnvironmentObject is instantiated in the AppDelegate: let settings = Settings()
So, all I had to do was to move MyPlayerDelgate down a line so it wasn't part of MeditationView anymore. Then settings referred to the global instance of Settings, and everything worked.
Upvotes: 0