小编典典

SwiftUI:如何使用@Binding 变量实现自定义初始化

all

我正在处理资金输入屏幕,需要实现自定义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
    }
    ...
}

阅读 259

收藏
2022-07-04

共1个答案

小编典典

啊!你是如此接近。这就是你的做法。你错过了一个美元符号(beta 3)或下划线(beta 4),或者在你的 amount 属性前面的 self ,或者在
amount 参数后面的 .value 。所有这些选项都有效:

你会看到我删除了@Statein 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 变量:

// Beta 3:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)

// Beta 4:
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
2022-07-04