I like to change a var in a struct from a View body. However, this throws in 'immutable value' error each time. After Googling, a mutating func
seems appropriate, but also this method throws the same error.
Minimum reproducible example below (tap the button > toggle the Bool in the struct > change the button color).
Note that in my original code it's not about changing the button color, but marking a quiz module as complete and updating some interface items and colors.
// Module.swift
import SwiftUI
struct Module: Identifiable {
var id = UUID()
var title: String
var complete: Bool
mutating func toggleComplete() {
complete.toggle()
}
}
var modules = [
Module(title: "Module 1", complete: false)
Module(title: "Module 2", complete: false)
]
// ModuleButton.swift
import SwiftUI
struct ModuleButton: View {
var module: Module
var body: some View {
Button(module.title){}
.padding(8)
.padding(.horizontal, 10)
.background(module.complete ? .green : .blue)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous))
.onTapGesture{
module.toggleComplete()
}
}
}
struct ModuleButton_Previews: PreviewProvider {
static var previews: some View {
ModuleButton(module: modules[0])
}
}
Some examples of how I got inspired to use mutating func
:
https://www.hackingwithswift.com/sixty/7/5/mutating-methods
As I said in my comment, module
should be an @State
variable. Here's a question explaining what @State
is: What does the SwiftUI `@State` keyword do?. See the question for more information on the background behind @State
. Here's how you should modify your code:
struct ModuleButton: View {
@State var module: Module //<<<--- Here!!!
var body: some View {
Button(module.title){}
.padding(8)
.padding(.horizontal, 10)
.background(module.complete ? .green : .blue)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous))
.onTapGesture{
//This now works
module.toggleComplete()
}
}
}