Search code examples
swiftaudioavfoundationavaudioplayerswiftui

Where to place code for audio playback in a SwiftUI app


Where is the best place to put code for audio playback in a SwiftUI based app, i.e. not having UIViewController classes? The sound I want to play is initiated by a view, so I'm thinking of putting it into the corresponding view model class. But as a model class is about data, I think there should be a better option. What's the best architecture?


Solution

  • Correct, the View shouldn't take care of data. And SwiftUI enforces this logic.

    You could create a Player class which takes care of playing the audio. And add it as an EnvironmentObject, so you can control it with your button in the View. You can then do sweet things like binding your play button to show different images depending on whether the player is... playing :)

    Update Code has been updated for Xcode 11 beta 4 (willChange instead of didChange)

    struct PlayerView : View {
        @EnvironmentObject private var player: Player
    
        var body: some View {
            Button(action: {
                self.player.pauseOrPlay()
            }) {
                Image(systemName: player.isPlaying ? "pause.circle.fill" : "play.circle.fill").font(.title).frame(minWidth: 44, minHeight: 44)
            }
        }
    }
    
    class Player: BindableObject {
        let willChange = PassthroughSubject<Player, Never>()
    
        var isPlaying: Bool = false {
            willSet {
                willChange.send(self)
            }
        }
    
        func pauseOrPlay() {
            // Code that toggles the audio on and off
        }
    }