I have a dictionary that contains various values I want to "filter" by. So I'm doing something like this
struct ExampleView : View {
@EnvironmentObject var externalData : ExternalData
var body: some View {
VStack {
ForEach(externalData.filters) { (v : (String, Bool)) in
Toggle(isOn: $externalData.filters[v.0], label: {
Text("\(v.0)")
})
}
}
}
}
final class ExternalData : BindableObject {
let didChange = PassthroughSubject<ExternalData, Never>()
init() {
filters["Juniper"] = true
filters["Beans"] = false
}
var filters : Dictionary<String, Bool> = [:] {
didSet {
didChange.send(self)
}
}
}
This question seems related, but putting dynamic didn't seem to help and I wasn't able to figure out how to do that NSObject inheritance thing in this case. Right now, this code as is gives me this error:
Cannot subscript a value of type 'Binding<[String : Bool]>' with an argument of type 'String'
But trying to move the $ around or use paren in various ways doesn't seem to help. How can I bind the toggles to the values in my dictionary? I could just make manual toggles for each value, but that makes fragile code since (among other reasons) the potential filter values are based on a dataset that might have new values at some point.
I'm aware that I should really sort the keys (in some way) before iterating over them so the ordering is consistent, but that clutters this example so I left that code out.
I managed to make is work by using a custom binding for each filter.
final class ExternalData: BindableObject {
let didChange = PassthroughSubject<Void, Never>()
var filters: Dictionary<String, Bool> = [:] {
didSet {
didChange.send(())
}
}
init() {
filters["Juniper"] = true
filters["Beans"] = false
}
var keys: [String] {
return Array(filters.keys)
}
func binding(for key: String) -> Binding<Bool> {
return Binding(getValue: {
return self.filters[key] ?? false
}, setValue: {
self.filters[key] = $0
})
}
}
The keys
property list the filters
keys as String
so that it can be displayed (using ForEach(externalData.keys)
)
The binding(for:)
method, create a custom Binding
for the given key. This binding is given to the Toggle
to read/write the current value in the wrapped dictionary.
The view code:
struct ExampleView : View {
@EnvironmentObject var externalData : ExternalData
var body: some View {
VStack {
ForEach(externalData.keys) { key in
Toggle(isOn: self.externalData.binding(for: key)) {
Text(key)
}
}
}
}
}
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