I'm probably not understanding the basics and confused, but I couldn't figure out the reason of things below. Ok, what I want to do is pass Int64 to sub view and show Toggles based on bits and set the bits back to parent view like this:
struct ContentView: View {
@State var bits: Int64 = 5
var body: some View {
Form {
Section {
SectionView(title: "Section", withBits: $bits)
} header: {
Text("Toggle")
}
}
}
}
struct SectionView: View {
let title: String
@Binding var bits: Int64
@State private var first: Bool
@State private var second: Bool
@State private var third: Bool
init(title: String, withBits: Binding<Int64>) {
self.title = title
self._bits = withBits
self.first = self.bits & 1 == 1
self.second = self.bits & 2 == 2
self.third = self.bits & 4 == 4
}
var body: some View {
VStack {
HStack {
Text(self.title)
}
HStack {
Toggle("Toggle 1", isOn: self.$first)
.onChange(of: self.first) { newValue in
if newValue {
self.bits |= 1
}
else {
self.bits &= ~1
}
}
}
HStack {
Toggle("Toggle 2", isOn: self.$second)
.onChange(of: self.second) { newValue in
if newValue {
self.bits |= 2
}
else {
self.bits &= ~2
}
}
}
HStack {
Toggle("Toggle 3", isOn: self.$third)
.onChange(of: self.third) { newValue in
if newValue {
self.bits |= 4
}
else {
self.bits &= ~4
}
}
}
}
.onChange(of: self.bits) { newValue in
print("bits: \(bits)")
}
}
}
But it won't compile. Saying "'self' used before all stored properties are initialized" error.
So I set default values to all Bool vars like this:
@State private var first: Bool = false
@State private var second: Bool = false
@State private var third: Bool = false
It compiles now but cannot overwrite them in int(), below lines are completely ignored.
self.first = self.bits & 1 == 1
self.second = self.bits & 2 == 2
self.third = self.bits & 4 == 4
Moving above three lines to onAppear() worked. But still I want to know why they won't be overwritten in init() and cleanest way.
Ok things are clear now. To make a long story short, we can't initialize @State property in init() just doing like this:
@State var bla: Int = 7
init() {
// This line won't work
self.bla = 0
}
because "bla" is a just reference to storage like pointer and so setting 0 to it won't reach to real storage in init(), it will be replaced with newly allocated real property with initial value 7 instead. That's the way SwiftUI is designed. Whole discussion is here: https://forums.swift.org/t/assignment-to-state-var-in-init-doesnt-do-anything-but-the-compiler-gened-one-works/35235/37
So the answer what we should do here to achieve to set initial value to @State real property in init() is like this:
self._first = State(wrappedValue: withBits.wrappedValue & 1 == 1)
self._second = State(wrappedValue: withBits.wrappedValue & 2 == 2)
self._third = State(wrappedValue: withBits.wrappedValue & 4 == 4)
Above actually allocate storage and set them to @State properties. By doing this, we can also have initial values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With