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

SwiftUI中如何保持原数据源与下游绑定同步并更新数据?

解决SwiftUI中编辑详情项同步更新原数据源的问题

你的问题核心在于Fruit是值类型,直接将fruit赋值给merchant.selection时会创建一份副本,详情页拿到的是独立的拷贝,修改它不会影响原数组中的元素。即便改成Binding类型,如果绑定的是这份副本,依然无法同步更新原数据源。

以下是两种可行的解决方案:

方法一:通过ID追踪选中项并创建绑定

步骤1:修正Fruit结构体

确保name为可变属性,且遵循Identifiable协议:

struct Fruit: Identifiable {
    let id = UUID()
    var name: String // 必须定义为var才能修改
}

步骤2:修改Merchant类

用选中项的ID替代直接存储Fruit实例,同时添加计算属性返回原数组中对应元素的绑定:

final class Merchant: ObservableObject {
    
    @Published
    var selection: Fruit.ID? // 存储选中水果的ID而非实例
    
    @Published
    var fruits = [
        Fruit(name: "Banana"),
        Fruit(name: "Apple")
    ]
    
    // 返回选中水果的绑定,供详情页使用
    var selectedFruit: Binding<Fruit>? {
        guard let id = selection, let index = fruits.firstIndex(where: { $0.id == id }) else {
            return nil
        }
        return $fruits[index]
    }
}

步骤3:更新FruitsView

点击按钮时存储选中项的ID,并通过计算属性传递绑定到详情页:

struct FruitsView: View {
    
    @EnvironmentObject var merchant: Merchant
            
    var body: some View {
        VStack {
            ForEach(merchant.fruits) { fruit in
                Button {
                    merchant.selection = fruit.id
                } label: {
                    Text(fruit.name)
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .sheet(item: $merchant.selection) { _ in
            if let selectedFruit = merchant.selectedFruit {
                FruitDetailView(item: selectedFruit)
            }
        }
    }
}

步骤4:修改FruitDetailView

接收Binding类型的item,修改时直接同步原数组:

struct FruitDetailView: View {

    @Binding var item: Fruit
    
    var body: some View {
        VStack {
            Text(item.name)
            Button("Press Me") {
                item.name = "Watermelon" // 此时修改会同步到原数据源
            }
        }
    }
}

方法二:直接传递数组元素的绑定

如果不想修改Merchant的selection类型,可以通过ForEach的绑定版本直接获取元素绑定:

修改FruitsView

struct FruitsView: View {
    
    @EnvironmentObject var merchant: Merchant
            
    var body: some View {
        VStack {
            // 遍历fruits的绑定数组,直接获取每个元素的Binding
            ForEach($merchant.fruits) { $fruit in
                Button {
                    merchant.selection = fruit
                } label: {
                    Text(fruit.name)
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .sheet(item: $merchant.selection) { _ in
            // 根据选中项的ID找到原数组中的索引,创建绑定
            if let index = merchant.fruits.firstIndex(where: { $0.id == merchant.selection?.id }) {
                FruitDetailView(item: $merchant.fruits[index])
            }
        }
    }
}

Fruit结构体和FruitDetailView的修改同方法一,此时点击修改按钮就能同步更新原数组中的水果名称。

内容的提问来源于stack exchange,提问作者bobby123uk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:17