Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot use mutating member on immutable value: 'self' is immutable in SwiftUI

Tags:

swiftui

For the following code, I am getting the following error. I don't know how to work around this. How can I call volumeCheck() upon the button click?

struct ContentView: View {

    var player = AVAudioPlayer()

    var body: some View {
        HStack {
            Button(action: {
                self.volumeCheck()
            }) {
                Text("Click to test chimes volume")
            }
        }
    }

    mutating func volumeCheck() {
        guard let url = Bundle.main.url(
            forResource: "chimes",
            withExtension: "mp3"
            ) else { return }

        do {
            player = try AVAudioPlayer(contentsOf: url)
            player.prepareToPlay()
            player.volume = Float(self.sliderValue)
            player.play()
        } catch let error {
            print(error.localizedDescription)
        }
        print("volume checked print")
    }
}
like image 733
ScottyBlades Avatar asked Sep 28 '19 06:09

ScottyBlades


2 Answers

The problem is that View is a struct and it's body field is a computed property with a nonmutating getter. In your code it happens mutating method to be called in that nonmutating getter. So all you need to do is put your player to some kind of model:

class Model {
    var player: AVPlayerPlayer()
}

struct ContentView: View {

    var model = Model()

    // player can be changed from anywhere
}

P.S. In some other cases you may want changes in your model be reflected in view so you'd have to add @ObservedObject just before model declaration.

Hope that helps

like image 119
glassomoss Avatar answered Sep 22 '22 06:09

glassomoss


You are trying to set player to a new object in volumeCheck(). Set the player in your initialiser:

struct ContentView: View {

    private var player: AVAudioPlayer?

    public init() {
        if let url = Bundle.main.url(forResource: "chimes",
                                     withExtension: "mp3") {
            self.player = try? AVAudioPlayer(contentsOf: url)
        }
    }

    var body: some View {
        HStack {
            Button("Click to test chimes volume") {
                self.volumeCheck()
                }   .disabled(player == nil)
        }
    }

    private func volumeCheck() {
        player?.prepareToPlay()
        player?.volume = Float(self.sliderValue)
        player?.play()
        print("volume checked print")
    }
}

Please note that you are using sliderValue in your code even though it is not defined anywhere.

like image 39
LuLuGaGa Avatar answered Sep 20 '22 06:09

LuLuGaGa