啊!你差一点就成功了。这就是你要做的。您漏掉了一个美元符号(beta 3)或下划线(beta 4),或者在amount属性前面的self,或者在amount参数后面的.value。所有这些选项都有效:
您将看到我在includeDecimal中删除了@State,检查最后的解释。
这是在使用属性(把self放在它前面):
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(amount: Binding<Double>) {
// self.$amount = amount // beta 3
self._amount = amount // beta 4
self.includeDecimal = round(self.amount)-self.amount > 0
}
}
或者在后面使用.value(但不使用self,因为你使用的是传入的形参,而不是结构体的属性):
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(amount: Binding<Double>) {
// self.$amount = amount // beta 3
self._amount = amount // beta 4
self.includeDecimal = round(amount.value)-amount.value > 0
}
}
这是相同的,但是我们为参数(withAmount)和属性(amount)使用了不同的名称,因此您可以清楚地看到您在使用它们。
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(withAmount: Binding<Double>) {
// self.$amount = withAmount // beta 3
self._amount = withAmount // beta 4
self.includeDecimal = round(self.amount)-self.amount > 0
}
}
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(withAmount: Binding<Double>) {
// self.$amount = withAmount // beta 3
self._amount = withAmount // beta 4
self.includeDecimal = round(withAmount.value)-withAmount.value > 0
}
}
注意,由于属性包装器(@Binding)创建了使.value变得不必要的访问器,因此.value对于属性来说不是必需的。然而,对于参数,没有这样的事情,您必须显式地做它。如果你想了解更多关于属性包装器的知识,请查看WWDC会议415 - Modern Swift API Design并跳转到23:12。
As you discovered, modifying the @State variable from the initilizer will throw the following error: Thread 1: Fatal error: Accessing State outside View.body. To avoid it, you should either remove the @State. Which makes sense because includeDecimal is not a source of truth. Its value is derived from amount. By removing @State, however, includeDecimal will not update if amount changes. To achieve that, the best option, is to define your includeDecimal as a computed property, so that its value is derived from the source of truth (amount). This way, whenever the amount changes, your includeDecimal does too. If your view depends on includeDecimal, it should update when it changes:
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal: Bool {
return round(amount)-amount > 0
}
init(withAmount: Binding<Double>) {
self.$amount = withAmount
}
var body: some View { ... }
}
正如rob mayoff所指出的,你也可以使用$$varName (beta 3),或_varName (beta4)来初始化一个状态变量:
// Beta 3:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
// Beta 4:
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)