Argh! Du warst so nah. Das ist wie man es macht. Sie haben ein Dollarzeichen (Beta 3) oder einen Unterstrich (Beta 4) verpasst und entweder sich selbst vor Ihrer Betragseigenschaft oder einen Wert nach dem Betragsparameter. Alle diese Optionen funktionieren:
Sie werden sehen, dass ich das @State
in includeDecimal entfernt habe. Überprüfen Sie die Erklärung am Ende.
Dies nutzt die Eigenschaft (stellen Sie sich davor):
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
}
}
oder mit .value after (aber ohne self, da Sie den übergebenen Parameter verwenden, nicht die Eigenschaft der Struktur):
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
}
}
Dies ist das gleiche, aber wir verwenden unterschiedliche Namen für den Parameter (withAmount) und die Eigenschaft (Betrag), sodass Sie deutlich sehen, wann Sie jeden verwenden.
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
}
}
Beachten Sie, dass der Wert für die Eigenschaft dank des Eigenschafts-Wrappers (@Binding) nicht erforderlich ist, der die Accessoren erstellt, die den Wert unnötig machen. Mit dem Parameter gibt es so etwas jedoch nicht und Sie müssen es explizit tun. Wenn Sie mehr über Property Wrapper erfahren möchten, lesen Sie die WWDC-Sitzung 415 - Modern Swift API Design und springen Sie zu 23:12.
Wie Sie festgestellt haben, wird beim Ändern der Variablen @State im Initilizer der folgende Fehler ausgegeben: Thread 1: Schwerwiegender Fehler: Zugriff auf den Status außerhalb von View.body . Um dies zu vermeiden, sollten Sie entweder den @State entfernen. Was Sinn macht, weil includeDecimal keine Quelle der Wahrheit ist. Sein Wert wird aus der Menge abgeleitet. Durch Entfernen von @State wird jedoch includeDecimal
nicht aktualisiert, wenn sich der Betrag ändert. Um dies zu erreichen, ist es am besten, Ihr includeDecimal als berechnete Eigenschaft zu definieren, damit sein Wert von der Quelle der Wahrheit (Menge) abgeleitet wird. Auf diese Weise funktioniert auch includeDecimal, wenn sich der Betrag ändert. Wenn Ihre Ansicht von includeDecimal abhängt, sollte sie aktualisiert werden, wenn sie sich ändert:
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 { ... }
}
Wie von rob mayoff angegeben , können Sie auch $$varName
(Beta 3) oder _varName
(Beta4) verwenden, um eine Statusvariable zu initialisieren:
$$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
derThread 1: Fatal error: Accessing State<Bool> outside View.body
@State
Variablen sollten eine Quelle der Wahrheit darstellen. Aber in Ihrem Fall duplizieren Sie diese Wahrheit, weil der Wert von includeDecimal aus Ihrer tatsächlichen Wahrheitsquelle abgeleitet werden kann, nämlich der Menge. Sie haben zwei Möglichkeiten: 1. Sie machen includeDecimal zu einer privaten Variable (kein @State) oder noch besser. 2. Sie machen es zu einer berechneten Eigenschaft, von der der Wert abgeleitet wirdamount
. Auf diese WeiseincludeDecimal
funktioniert es auch , wenn sich der Betrag ändert . Sie sollten es so deklarieren:private var includeDecimal: Bool { return round(amount)-amount > 0 }
und entfernen Sie dieself.includeDecimal = ...
includeDecimal
also brauche ich es als @ State Variable in der Ansicht. Ich möchte es wirklich nur mit einem Startwert initialisieren.value
durch ersetzt.wrappedValue
, wäre schön die Antwort zu aktualisieren und Beta-Optionen zu entfernen.Sie sagten (in einem Kommentar): "Ich muss mich ändern können.
includeDecimal
" Was bedeutet es zu ändernincludeDecimal
? Sie möchten es anscheinend basierend darauf initialisieren, obamount
(zur Initialisierungszeit) eine Ganzzahl ist. In Ordnung. So was passiert , wennincludeDecimal
istfalse
und dann später Sie es änderntrue
? Wirst du irgendwie zwingenamount
, dann nicht ganzzahlig zu sein?Wie auch immer, Sie können nicht ändern
includeDecimal
ininit
. Sie können es jedoch folgendermaßen initialisiereninit
: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
(Beachten Sie, dass an einem gewissen Punkt die
$$includeDecimal
Syntax geändert werden_includeDecimal
.)quelle
Da es Mitte 2020 ist, lassen Sie uns noch einmal zusammenfassen:
Bezüglich
@Binding amount
_amount
wird nur zur Verwendung während der Initialisierung empfohlen. Und niemalsself.$amount = xxx
während der Initialisierung so zuweisenamount.wrappedValue
undamount.projectedValue
werden nicht häufig verwendet, aber Sie können Fälle wie sehen@Environment(\.presentationMode) var presentationMode self.presentationMode.wrappedValue.dismiss()
@Binding var showFavorited: Bool Toggle(isOn: $showFavorited) { Text("Change filter") }
quelle