I'm using the swift package [Defaults
][1] to manage a list of preferences in my app.
One of this property is an array of structures that I get using @Default(.list) var list
.
In Swift UI, I loop on this list to edit the various elements.
@Default(.list) var list;
ForEach($list, id: \.wrappedValue.id) { element in
...
}
It's working fine and it works as expected.
My problem is that I need to filter this list.
I'm using $list.filter(...)
but I get a warning Conformance of 'Binding<Value>' to 'Sequence' is only available in MacOS 12.0
.
Unfortunately, my app needs to run on MacOS 11.x.
I don't really understand what the warning means and how I can adapt my code to make it works with MacOS 11.x.
Thanks!
-- Update --
struct Stock: Codable, Identifiable, DefaultsSerializable {
var id: String
var currency: String = "USD"
}
extension Defaults.Keys {
static let stocks = Key<[Stock]>("stocks", default: [])
}
struct StocksView: View {
@Default(.stocks) var stocks
func filterStocks(stock: Stock) -> Bool
{
return stock.currency == "USD"
}
var body: some View {
ForEach($stocks.filter(filterStocks, id: \.wrappedValue.id) { stock in
....
}
}
}
extension Binding where Value == [Stock] {//where String is your type
func filter(_ condition: @escaping (Stock) -> Bool) -> Binding<Value> {//where String is your type
return Binding {
return wrappedValue.filter({condition($0)})
} set: { newValue in
wrappedValue = newValue
}
}
}
[1]: https://github.com/sindresorhus/Defaults
CodePudding user response:
When you use $list.filter
your are not filtering list
you're filtering Binding<[List]>
which doesn't conform to the protocol Sequence.
Add this extension to your project and see if it works
extension Binding where Value == [String] {//where String is your type
func filterB(_ condition: @escaping (String) -> Bool) -> Binding<Value> {//where String is your type
return Binding {
return wrappedValue.filter({condition($0)})
} set: { newValue in
wrappedValue = newValue
}
}
}
Edit: Binding
in a ForEach
requires SwiftUI 3
However, you can pass the normal array and whenever you need a Binding
use this function:
extension Stock {
func binding(_ array: Binding<[Stock]>) -> Binding<Stock> {
Binding {
self
} set: { newValue in
guard let index = array.wrappedValue.firstIndex(where: {$0.id == newValue.id}) else {return}
array.wrappedValue[index] = newValue
}
}
}
So your code would look like this:
ForEach(stocks.filter(filterStocks), id: \.id) { stock in
....
SomeViewRequiringBinding(value: stock.binding(stocks))
}