SwiftUI 如何在类中创建指向结构体实例的快捷绑定/引用
问题原因
Item属于值类型(Swift结构体默认是值类型),所有赋值操作都会生成独立的内存拷贝,你当前直接把数组中的Item实例赋值给selection属性,实际存储的是和数组内元素完全独立的副本,修改副本自然不会同步到原数组中的对应实例。
疑问解答
@Binding是专门用于SwiftUI视图层级的属性包装器,禁止在ObservableObject类中使用。如果要在Model层持有快捷引用,直接声明为Binding<Item>?类型即可,不需要添加@Published修饰,Binding本身不负责发布状态变更,修改元素后触发视图刷新依赖数组的@Published属性。- 更推荐的工业级常规方案是存储选中元素的唯一ID而非实例或Binding,实现简单且不存在引用失效的问题,稳定性更高。
最优实现方案(存选中ID)
直接修改你的代码如下即可实现需求:
import SwiftUI struct Item: Identifiable, Equatable { var id = UUID().uuidString var color: Color } class Model: ObservableObject { @Published var items: [Item] = [Item(color: .blue), Item(color: .blue), Item(color: .blue)] // 存储选中项的ID @Published var selectionId: Item.ID? func setSelection(itemId: Item.ID) { selectionId = itemId } func changeColor(color: Color) { // 匹配ID找到数组中的原始元素修改 guard let index = items.firstIndex(where: { $0.id == selectionId }) else { return } items[index].color = color } } struct ContentView: View { @StateObject var model = Model() var body: some View { VStack { ForEach($model.items) { $item in SubView(item: $item, model: model) } Button { model.changeColor(color: .red) } label: {Text("Make Selection Red")} }.padding() } } struct SubView: View { @Binding var item: Item var model: Model var body: some View { VStack { Button { // 传入当前item的ID model.setSelection(itemId: item.id) } label: { Text("Select").background(item.color) }.buttonStyle(PlainButtonStyle()) } } }
Binding快捷引用方案(可选)
如果你确实需要用Binding实现快捷引用的效果,可以采用以下实现,注意数组元素删除后要主动清空selection避免野引用:
class Model: ObservableObject { @Published var items: [Item] = [Item(color: .blue), Item(color: .blue), Item(color: .blue)] // 类中直接声明Binding类型,不加@Binding和@Published var selection: Binding<Item>? func setSelection(item: Binding<Item>) { selection = item } func changeColor(color: Color) { selection?.wrappedValue.color = color } } // SubView对应修改点击逻辑 struct SubView: View { @Binding var item: Item var model: Model var body: some View { VStack { Button { // 直接传入当前的Binding对象 model.setSelection(item: $item) } label: { Text("Select").background(item.color) }.buttonStyle(PlainButtonStyle()) } } }
内容的提问来源于stack exchange,提问作者Jayåk
相关产品推荐
相关产品推荐

