在我遵循的Ray教程中,我设置了以下属性
struct ContentView : View {
var rTarget = Double.random(in: 0..<1)
var gTarget = Double.random(in: 0..<1)
var bTarget = Double.random(in: 0..<1)
}
这些当然是不可变的,因此除非我将该功能标记为变异的,否则我无法通过功能对其进行修改
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
但是我从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
但是我不能将var body
标记为mutating
var
'mutating' may only be used on 'func' declarations
因此,在这一点上,我想在用户每次点击警报按钮时重置xTarget
的值,但我不知道此时的良好做法。
答案 0 :(得分:1)
很难说出您的建议是什么,因为在您的示例中,您没有向我们展示目标变量的实际用途。
但是,我认为可以肯定地说,在SwiftUI视图中,需要随时间变化的变量必须是@State或您可用的绑定类型之一。否则,它很可能必须是不变的。
一切都取决于确定什么是“真理之源”。如果这些目标是视图的内部对象,则使用@State,如果真相的来源位于视图的外部,则可以使用可绑定选项之一。
我强烈建议您花37分钟的时间观看WWDC2019,第226节(通过SwiftUI的数据流)。它将清除您对此的所有疑问。
如果您着急,请跳至5:45。但是我建议您看整个过程。最终将节省您的时间。
如果您不知道“真理的源头”是什么。然后,您绝对应该观看会议。
答案 1 :(得分:1)
我正在写同一篇文章。
我没有遇到这个问题,因为我已经在使用@State
属性包装器。
正如 kontiki 所建议的,Session 226(通过SwiftUI的数据流)非常适合理解在更新不同数据源时如何使用哪个属性包装器。
如果您想知道@State this answer是什么,那么
这是我的代码:
@State var rTarget = Double.random(in: 0..<1)
@State var gTarget = Double.random(in: 0..<1)
@State var bTarget = Double.random(in: 0..<1)
@State var rGuess: Double
@State var gGuess: Double
@State var bGuess: Double
答案 2 :(得分:0)
这时我发现的唯一解决方案是也将xTarget
道具标记为@State
并对其进行修改而不会使功能发生变化
@State private var rTarget = Double.random(in: 0..<1)
@State private var gTarget = Double.random(in: 0..<1)
@State private var bTarget = Double.random(in: 0..<1)
但是我不清楚这是一种好习惯。
答案 3 :(得分:0)
这个问题很古老,但是如果没有更多的上下文,很难理解和理解答案。问题来自RayWenderlich - SwiftUI: Getting Started。
在发出警报后,您需要做两件事以重置游戏:
mutating
中删除displayAlert()
@State
,rTarget
,gTarget
)之前添加bTarget
完整代码供参考-请注意,我使用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
}
}