SwiftUI适配macOS11时Binding数组filter兼容性问题
警告触发原因
- 苹果从macOS 12(iOS 15)开始,才为
Binding<Collection>类型实现了Sequence协议适配,允许直接对Binding包裹的集合调用filter等序列方法并保留双向绑定能力,在低版本系统调用这类方法就会抛出你看到的可用性警告。 - 你当前自定义的
Binding<[Stock]>.filter扩展存在逻辑缺陷:它返回的是过滤后子数组的独立Binding,当你在ForEach中修改过滤后的元素时,setter会把过滤后的子数组直接赋值给原stocks数组,会导致所有不符合过滤条件的元素被意外删除,无法满足正常编辑需求。
macOS 11 兼容实现方案
你需要实现的逻辑是:从原数组的Binding中,提取所有符合过滤条件的单个元素的Binding,而非生成一个截断后的新数组Binding,这样编辑单个元素时只会更新原数组对应位置的值,不会影响未被过滤的元素。
- 先添加如下通用扩展,不限制具体元素类型:
extension Binding where Value: MutableCollection & RangeReplaceableCollection, Value.Element: Identifiable { func filtered(_ isIncluded: @escaping (Value.Element) -> Bool) -> [Binding<Value.Element>] { wrappedValue .enumerated() .filter { isIncluded($0.element) } .map { index, _ in Binding( get: { wrappedValue[index] }, set: { wrappedValue[index] = $0 } ) } } }
- 替换视图中的ForEach代码,直接调用扩展方法获取过滤后的元素Binding数组即可:
struct StocksView: View { @Default(.stocks) var stocks func filterStocks(stock: Stock) -> Bool { stock.currency == "USD" } var body: some View { ForEach($stocks.filtered(filterStocks)) { $stock in // 此处直接使用$stock做双向绑定编辑,不会影响未通过过滤的元素 // ... } } }
该实现完全不依赖macOS 12新增的Binding序列协议能力,可正常在macOS 11及以上版本运行,且不会出现修改内容时丢失未过滤元素的问题。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

