I made a test code for inverted bool binding as following, including almost binding ways I can think of(except @Environment...).
struct TestView: View {
@State private var isOn: Bool = false
@State private var parameter: Parameter = .init()
@StateObject private var vm = ViewModel()
var body: some View {
VStack {
Toggle("isOff = \(isOn.description)", isOn: !$isOn)
Toggle("isOff = \(parameter.isOn.description)", isOn: !$parameter.isOn)
Toggle("isOff = \(vm.isOn.description)", isOn: !$vm.isOn)
Toggle("isOff = \(vm.parameter.isOn.description)", isOn: !$vm.parameter.isOn)
InnerView { isOn in
Toggle("isOff = \(isOn.wrappedValue.description)", isOn: !isOn)
} t2: { parameter in
Toggle("isOff = \(parameter.wrappedValue.isOn.description)", isOn: !parameter.isOn)
}
}
.padding()
}
@MainActor
class ViewModel: ObservableObject {
@Published var isOn: Bool = false
@Published var parameter: Parameter = .init()
}
struct Parameter {
var isOn: Bool = false
}
struct InnerView<T>: View where T: View {
@State private var isOn: Bool = false
@State private var parameter: Parameter = .init()
@StateObject private var vm: ViewModel = .init()
let t1: (Binding<Bool>) -> T
let t2: (Binding<Parameter>) -> T
var body: some View {
VStack {
t1($isOn)
t2($parameter)
t1($vm.isOn)
t1($vm.parameter.isOn)
}
}
}
}
Q1: here define the prefix operator ! in 2 ways: global and extension binding. which works? They don't conflict if put together, and if comment one and the other works fine.
prefix operator !
prefix func !(value: Binding<Bool>) -> Binding<Bool> {
Binding<Bool>(
get: { !value.wrappedValue },
set: { value.wrappedValue = !$0 }
)
}
extension Binding where Value == Bool {
static prefix func !(value: Binding<Bool>) -> Binding<Bool> {
Binding<Bool>(
get: { !value.wrappedValue },
set: { value.wrappedValue = !$0 }
)
}
}
if I comment the global one, and change extension one like following, strange things happened, compile success and run run crash.
//prefix operator !
//
//prefix func !(value: Binding<Bool>) -> Binding<Bool> {
// Binding<Bool>(
// get: { !value.wrappedValue },
// set: { value.wrappedValue = !$0 }
// )
//}
extension Binding where Value == Bool {
static prefix func !(value: Binding<Bool>) -> Binding<Bool> {
!value
}
}
Q2: if I put the prefix operator ! definition into a Swift Package framework, some tests will compile failed as 'Cannot convert value of type 'Binding' to expected argument type 'Bool'. Cannot convert value of type 'Bool' to expected argument type 'Binding''. Is it a wrong way to define or some problems about Swift Package?
Q3: in 'Toggle("isOff = (vm.isOn.description)", isOn: !$vm.isOn)', $vm is a binding< ViewModel >, isON is Bool, is $vm.isON a binding< Bool >? I think it is. But if not, what's it? if not, the operator cannot be used on it, right? I'm kind of confused.