我正在处理资金输入屏幕,需要实现自定义init以根据初始化金额设置状态变量。
init
我认为这会起作用,但我得到一个编译器错误:
Cannot assign value of type 'Binding<Double>' to type 'Double'
struct AmountView : View { @Binding var amount: Double @State var includeDecimal = false init(amount: Binding<Double>) { self.amount = amount self.includeDecimal = round(amount)-amount > 0 } ... }
啊!你是如此接近。这就是你的做法。你错过了一个美元符号(beta 3)或下划线(beta 4),或者在你的 amount 属性前面的 self ,或者在 amount 参数后面的 .value 。所有这些选项都有效:
你会看到我删除了@Statein includeDecimal,检查最后的解释。
@State
includeDecimal
这是使用属性(将 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 } }
请注意,属性不需要 .value,这要归功于属性包装器 (@Binding),它创建了使 .value 变得不必要的访问器。 但是,使用参数,没有这样的事情,你必须明确地做到这一点。如果您想了解有关属性包装器的更多信息,请查看WWDC 会话 415 - 现代 Swift API 设计并跳转到 23:12。
正如您所发现的,从初始化程序修改 @State 变量将引发以下错误: _ 线程 1:致命错误:访问 View.body 外部的状态_ 。为避免这种情况,您应该删除@State。这是有道理的,因为 includeDecimal 不是事实的来源。它的价值来源于数量。但是,通过删除 @State,includeDecimal如果数量发生变化,则不会更新。为了实现这一点,最好的选择是将您的 includeDecimal 定义为计算属性,以便它的值来自事实来源(数量)。这样,每当金额发生变化时,您的 includeDecimal 也会发生变化。如果您的视图依赖于 includeDecimal,它应该在更改时更新:
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) 来初始化 State 变量:
$$varName
_varName
// Beta 3: $$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0) // Beta 4: _includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)