You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 13:48:02