¡Argh! Estabas tan cerca. Así es como lo haces. Se perdió un signo de dólar (beta 3) o un guión bajo (beta 4), y usted mismo frente a su propiedad de monto, o .value después del parámetro de monto. Todas estas opciones funcionan:
Verá que @State
eliminé el includeDecimal, verifique la explicación al final.
Esto está usando la propiedad (poner self delante de ella):
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
}
}
o usando .value después (pero sin self, porque está usando el parámetro pasado, no la propiedad de la estructura):
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
}
}
Esto es lo mismo, pero usamos diferentes nombres para el parámetro (withAmount) y la propiedad (amount), por lo que puede ver claramente cuándo está usando cada uno.
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
}
}
Tenga en cuenta que .value no es necesario con la propiedad, gracias al contenedor de propiedades (@Binding), que crea los descriptores de acceso que hacen innecesario el .value. Sin embargo, con el parámetro, no existe tal cosa y hay que hacerlo explícitamente. Si desea obtener más información sobre los envoltorios de propiedades, consulte la sesión 415 de la WWDC: Diseño de API Swift moderno y pase a las 23:12.
Como descubrió, la modificación de la variable @State desde el initilizer arrojará el siguiente error: Subproceso 1: Error fatal: Accediendo al Estado fuera de View.body . Para evitarlo, debe eliminar el @State. Lo cual tiene sentido porque includeDecimal no es una fuente de verdad. Su valor se deriva de la cantidad. Sin embargo, al eliminar @State, includeDecimal
no se actualizará si cambia la cantidad. Para lograrlo, la mejor opción es definir su includeDecimal como una propiedad calculada, de modo que su valor se derive de la fuente de verdad (cantidad). De esta manera, siempre que cambie la cantidad, su includeDecimal también lo hará. Si su vista depende de includeDecimal, debería actualizarse cuando cambie:
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 { ... }
}
Como lo indica rob mayoff , también puede usar $$varName
(beta 3) o _varName
(beta4) para inicializar una variable de estado:
$$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
deThread 1: Fatal error: Accessing State<Bool> outside View.body
@State
las variables deben representar una fuente de verdad. Pero en su caso, está duplicando esa verdad, porque el valor de includeDecimal puede derivarse de su fuente real de verdad que es la cantidad. Tiene dos opciones: 1. Hace que includeDecimal sea una variable privada (sin @State), o incluso mejor 2. Lo convierte en una propiedad calculada que deriva su valoramount
. De esta manera, si la cantidad cambia,includeDecimal
también lo hace. Debería declararlo así:private var includeDecimal: Bool { return round(amount)-amount > 0 }
y eliminar elself.includeDecimal = ...
includeDecimal
así que lo necesito como una variable @State en la vista. Realmente solo quiero inicializarlo con un valor inicial.value
ha sido reemplazado por.wrappedValue
, sería bueno actualizar la respuesta y eliminar las opciones beta.Dijiste (en un comentario) "Necesito poder cambiar
includeDecimal
". ¿Qué significa cambiarincludeDecimal
? Aparentemente, desea inicializarlo en función de siamount
(en el momento de la inicialización) es un número entero. Bueno. Entonces, ¿qué sucede siincludeDecimal
esfalse
y luego lo cambia atrue
? ¿Vas a forzar de alguna maneraamount
a ser no entero?De todos modos, no puedes modificar
includeDecimal
eninit
. Pero puedes inicializarloinit
, así: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
(Tenga en cuenta que en algún momento
$$includeDecimal
se cambiará la sintaxis_includeDecimal
).fuente
Ya que es mediados de 2020, recapitulemos:
En cuanto a
@Binding amount
_amount
solo se recomienda su uso durante la inicialización. Y nunca asigne de esta maneraself.$amount = xxx
durante la inicializaciónamount.wrappedValue
yamount.projectedValue
no se utilizan con frecuencia, pero puede ver casos como@Environment(\.presentationMode) var presentationMode self.presentationMode.wrappedValue.dismiss()
@Binding var showFavorited: Bool Toggle(isOn: $showFavorited) { Text("Change filter") }
fuente