Dans le tutoriel de Ray que je suis, j'ai les propriétés suivantes définies
struct ContentView : View {
var rTarget = Double.random(in: 0..<1)
var gTarget = Double.random(in: 0..<1)
var bTarget = Double.random(in: 0..<1)
}
Ce sont bien sûr immuables donc je ne peux pas les modifier à partir d'un func à moins que je ne marque ce func comme étant en mutation
func reset() {
rTarget = Double.random(in: 0..<1)
gTarget = Double.random(in: 0..<1)
bTarget = Double.random(in: 0..<1)
}
Cannot assign to property: 'self' is immutable
Mais j'appelle cette fonction de var body
mutating func reset() {
rTarget = Double.random(in: 0..<1)
gTarget = Double.random(in: 0..<1)
bTarget = Double.random(in: 0..<1)
}
fileprivate mutating func displayAlert() -> Alert {
return Alert(title: Text("Your Score"), message: Text("\(computeScore())"), dismissButton: Alert.Button.destructive(Text("Ok"), onTrigger: {
self.reset()
}))
}
var body: some View {
Button(action: {
self.showAlert = true
}) {
Text("Hit Me!")
}.presentation($showAlert) {
displayAlert()
}
}
Cannot use mutating member on immutable value: 'self' is immutable
Mais je ne peux pas marquer var body
comme mutating
var
'mutating' may only be used on 'func' declarations
Donc, à ce stade, je veux réinitialiser les valeurs xTarget
chaque fois que l'utilisateur appuie sur le bouton d'alerte et je ne sais pas quelle sera la bonne pratique à ce stade.
Cette question est ancienne, mais elle est un peu difficile à suivre et à comprendre les réponses sans plus de contexte. La question vient de RayWenderlich - SwiftUI: Getting Started .
Vous devez faire deux choses pour réinitialiser le jeu après la présentation de l'alerte:
mutating
de votre fonction displayAlert()
@State
Devant les variables que vous souhaitez modifier (c'est-à-dire rTarget
, gTarget
, bTarget
)Code complet pour référence - Notez que je réinitialise le jeu en utilisant func resetGame()
import SwiftUI
struct ContentView: View {
// In SwiftUI, when a @State variable changes,
// the view invalidates its appearance and recomputes the body.
@State var randomRed = Double.random(in: 0..<1)
@State var randomGreen = Double.random(in: 0..<1)
@State var randomBlue = Double.random(in: 0..<1)
@State var redGuess: Double
@State var greenGuess: Double
@State var blueGuess: Double
@State var showAlert: Bool = false
func calculateScore() -> String {
// The diff value is just the distance between two points in three-dimensional space.
// You subtract it from 1, then scale it to a value out of 100.
// Smaller diff yields a higher score.
let redDiff = redGuess - randomRed
let greenDiff = greenGuess - randomGreen
let blueDiff = blueGuess - randomBlue
let diff = sqrt(redDiff * redDiff + greenDiff * greenDiff + blueDiff * blueDiff)
return "\(Int((1.0 - diff) * 100.0 + 0.5))"
}
func resetGame() {
randomRed = Double.random(in: 0..<1)
randomGreen = Double.random(in: 0..<1)
randomBlue = Double.random(in: 0..<1)
redGuess = 0.5
greenGuess = 0.5
blueGuess = 0.5
}
var body: some View {
VStack {
HStack {
VStack {
Color(red: randomRed, green: randomGreen, blue: randomBlue)
Text("Match this color")
}
VStack {
Color(red: redGuess, green: greenGuess, blue: blueGuess)
Text("R: \(Int(redGuess * 255)) G: \(Int(greenGuess * 255)) B: \(Int(blueGuess * 255))")
}
}
Button(action: {self.showAlert = true} ) {
Text("Hit me")
}.alert(isPresented: $showAlert, content: {
Alert(title: Text("Your Score"), message: Text(self.calculateScore()),
dismissButton: Alert.Button.default(Text("OK"), action: { self.resetGame()
}))
}).padding()
ColorSlider(value: $redGuess, textColor: .red)
ColorSlider(value: $greenGuess, textColor: .green)
ColorSlider(value: $blueGuess, textColor: .blue)
}
}
}
struct ColorSlider: View {
// Use @Binding instead of @State, because the ColorSlider view
// doesn't own this data—it receives an initial value from its parent view and mutates it.
@Binding var value: Double
var textColor: Color
var body: some View {
HStack {
Text("0").foregroundColor(textColor)
Slider(value: $value)
Text("255").foregroundColor(textColor)
}.padding(.horizontal) // Add some space before & after the text
}
}