Ах! Вы были так близки. Вот как вы это делаете. Вы пропустили знак доллара (бета 3) или подчеркивание (бета 4) и либо self перед свойством amount, либо .value после параметра amount. Все эти варианты работают:
Вы увидите, что я удалил @State
in includeDecimal, проверьте объяснение в конце.
Это использует свойство (поместите перед ним self):
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(amount: Binding<Double>) {
self._amount = amount
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
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
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
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 { ... }
}
Как указал Роб Майофф , вы также можете использовать $$varName
(beta 3) или _varName
(beta4) для инициализации переменной State:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
self.includeDecimal = round(self.amount)-self.amount > 0
изThread 1: Fatal error: Accessing State<Bool> outside View.body
@State
переменные должны представлять источник истины. Но в вашем случае вы дублируете эту истину, потому что значение includeDecimal может быть получено из вашего фактического источника истины, то есть количества. У вас есть два варианта: 1. Сделать includeDecimal частной переменной (без @State) или даже лучше 2. Вы сделаете ее вычисляемым свойством, из которого выводится его значениеamount
. Таким образом, если сумма изменится,includeDecimal
тоже. Вы должны объявить это так:private var includeDecimal: Bool { return round(amount)-amount > 0 }
и удалитьself.includeDecimal = ...
includeDecimal
поэтому он нужен как переменная @State в представлении. Я действительно просто хочу инициализировать его начальным значением.value
был заменен на.wrappedValue
, было бы неплохо обновить ответ и удалить параметры бета.Вы сказали (в комментарии): «Мне нужно иметь возможность измениться
includeDecimal
». Что значит изменитьincludeDecimal
? Очевидно, вы хотите инициализировать его в зависимости от того, является лиamount
(во время инициализации) целым числом. Ладно. Итак, что произойдет, еслиincludeDecimal
будет,false
а потом вы измените его наtrue
? Собираетесь ли вы как-то заставитьamount
потом быть нецелым числом?Во всяком случае, вы не можете изменить
includeDecimal
вinit
. Но вы можете инициализировать егоinit
так:struct ContentView : View { @Binding var amount: Double init(amount: Binding<Double>) { $amount = amount $$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0) } @State private var includeDecimal: Bool
(Обратите внимание , что в какой - то момент
$$includeDecimal
синтаксис будет изменен_includeDecimal
.)источник
Поскольку сейчас середина 2020 года, подведем итоги:
Относительно
@Binding amount
_amount
рекомендуется использовать только во время инициализации. И никогда не назначайте таким образомself.$amount = xxx
во время инициализацииamount.wrappedValue
иamount.projectedValue
не часто используются, но вы можете увидеть такие случаи, как@Environment(\.presentationMode) var presentationMode self.presentationMode.wrappedValue.dismiss()
@Binding var showFavorited: Bool Toggle(isOn: $showFavorited) { Text("Change filter") }
источник