SwiftUI中如何创建值为@State的字典?Toggle绑定报错怎么解决?
问题解析与解决方案
为什么$flags[name]无法返回Binding<Bool>?
SwiftUI的Binding类型并未针对字典([Key: Value])提供直接返回Binding<Value>的下标实现。当你尝试写$flags[name]时,Swift的类型推断会错误匹配到Binding针对集合的Range下标(而非字典的键下标),直接导致类型不匹配报错。另外,字典本身的下标返回的是可选值(Value?),即便存在对应的Binding下标,也会返回Binding<Bool?>,而Toggle要求的是Binding<Bool>,这也会引发类型兼容问题。
解决方案
方法一:手动创建自定义Binding
在循环中针对每个name手动构建Binding<Bool>,明确处理取值和赋值逻辑:
struct MyView : View { var names: [String] @State private var flags = [String : Bool]() var body: some View { ForEach(names, id: \.self) { name in Toggle(isOn: Binding( get: { self.flags[name, default: false] }, set: { self.flags[name] = $0 } )) { Text(name) } } .onAppear { for name in names { flags[name] = false } } } }
这里利用字典的default下标确保取值时始终得到非可选的Bool,赋值时直接更新字典对应键的值。
方法二:扩展Binding类型
给Binding<[String: Bool]>添加自定义下标,让$flags[name]可以直接返回Binding<Bool>:
extension Binding where Value == [String: Bool] { subscript(key: String) -> Binding<Bool> { Binding( get: { self.wrappedValue[key, default: false] }, set: { self.wrappedValue[key] = $0 } ) } } // 使用时和你原本的代码一致: struct MyView : View { var names: [String] @State private var flags = [String : Bool]() var body: some View { ForEach(names, id: \.self) { name in Toggle(isOn: $flags[name]) { Text(name) } } .onAppear { for name in names { flags[name] = false } } } }
这种方式适合需要多处使用字典Binding下标的场景,代码更简洁。
方法三:改用数组存储状态(场景受限)
如果names的顺序固定且不会动态变化,可以将flags改为数组,通过索引绑定:
struct MyView : View { var names: [String] @State private var flags: [Bool] = [] var body: some View { ForEach(Array(names.enumerated()), id: \.element) { index, name in Toggle(isOn: $flags[index]) { Text(name) } } .onAppear { flags = Array(repeating: false, count: names.count) } } }
注意:若names后续会动态增删,这种方法会导致索引与数据不匹配,需谨慎使用。
内容的提问来源于stack exchange,提问作者meaning-matters
相关产品推荐
相关产品推荐

