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

SwiftUI中通过Toggle更新数组内结构体Bool值的问题

SwiftUI Toggle更新数组结构体Bool值问题解决

问题背景

我是Swift和SwiftUI新手,现在遇到一个问题:想通过Toggle组件更新数组中某个结构体的Bool类型属性dataB,流程是点击首页面的NavigationLink跳转到Toggle所在页面,选定对应的结构体进行修改。附上简化代码,求帮忙,甚至不知道该搜什么关键词,提前感谢。

现有代码

文件1:数据模型定义

import Foundation

struct DataModel: Identifiable {
    let id = UUID()
    let phoneExtension: Int
    var dataA: String
    var dataB: Bool

    mutating func toggleDataB() {
        dataB.toggle()
    }
}

var dataSet: [DataModel] = [
    DataModel(phoneExtension: 1000, dataA: "Hi Ho", dataB: true),
    DataModel(phoneExtension: 2000, dataA: "Hi Ho", dataB: false),
    DataModel(phoneExtension: 3000, dataA: "Please", dataB: true),
    DataModel(phoneExtension: 4000, dataA: "Work", dataB: false),
    DataModel(phoneExtension: 5000, dataA: "For Me", dataB: true)
]

文件2:首页面

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationView{
            List{
                ForEach(dataSet.indices, id: \.self) { index in
                    NavigationLink("\(dataSet[index].phoneExtension)", destination: PlaygroundSecondPage(dataIsOn: dataSet[index].dataB, index: index))
                        .foregroundColor(dataSet[index].dataB ? .black : .blue)

                }
            }
        }
    }
}

文件3:Toggle修改页面

import SwiftUI

struct PlaygroundSecondPage: View {
    
    @State var dataIsOn: Bool
    var index: Int
    
    var body: some View {
        VStack{
            Text("dataIsOn: \(dataIsOn), in dataset: \(dataSet[index].dataB)")
            Toggle(
                isOn: $dataIsOn,
                label: {
                    Text("Toggle:")
                })
            .onChange(of: dataIsOn) {
                updateB()
            }
        }
    }
    
    func updateB() {
        dataSet[index].toggleDataB()
    }
}

问题根源

  1. 全局数组无状态监听:当前dataSet是全局变量,SwiftUI无法感知它的变化,就算修改了dataB,首页面的UI也不会自动更新。
  2. 值类型传递副本:DataModel是值类型,传递dataSet[index].dataB给PlaygroundSecondPage的dataIsOn时,传递的是副本。修改dataIsOn只是修改本地状态,和原数组的dataB不会自动同步,就算调用toggleDataB(),因为数组是值类型,修改的也是数组元素的副本,原数组没被真正修改(或者修改后UI没感知)。

修复方案

步骤1:用Observable类管理数据(iOS17+可用@Observable,更早版本用ObservableObject)

修改文件1,把数据放到可被SwiftUI监听的类中:

import Foundation
import SwiftUI

// iOS17+ 用@Observable,更简洁
@Observable
class DataStore {
    var dataSet: [DataModel] = [
        DataModel(phoneExtension: 1000, dataA: "Hi Ho", dataB: true),
        DataModel(phoneExtension: 2000, dataA: "Hi Ho", dataB: false),
        DataModel(phoneExtension: 3000, dataA: "Please", dataB: true),
        DataModel(phoneExtension: 4000, dataA: "Work", dataB: false),
        DataModel(phoneExtension: 5000, dataA: "For Me", dataB: true)
    ]
}

struct DataModel: Identifiable {
    let id = UUID()
    let phoneExtension: Int
    var dataA: String
    var dataB: Bool

    mutating func toggleDataB() {
        dataB.toggle()
    }
}

步骤2:修改首页面,注入数据仓库并传递绑定

import SwiftUI

struct ContentView: View {
    // 创建数据仓库实例,用@StateObject保证生命周期和视图一致
    @StateObject private var dataStore = DataStore()
    
    var body: some View {
        NavigationView{
            List{
                // 遍历dataStore的dataSet,直接拿到元素的绑定
                ForEach($dataStore.dataSet) { $model in
                    NavigationLink("\(model.phoneExtension)", destination: PlaygroundSecondPage(model: $model))
                        .foregroundColor(model.dataB ? .black : .blue)
                }
            }
        }
    }
}

步骤3:修改Toggle页面,直接绑定到模型的dataB

import SwiftUI

struct PlaygroundSecondPage: View {
    // 接收模型的绑定,直接和原数据关联
    @Binding var model: DataModel
    
    var body: some View {
        VStack{
            Text("dataIsOn: \(model.dataB), in dataset: \(model.dataB)")
            Toggle(
                isOn: $model.dataB,
                label: {
                    Text("Toggle:")
                })
            // 不需要额外的onChange,绑定会自动同步数据
        }
    }
}

说明

  • 用@Observable(或ObservableObject)让SwiftUI能监听数据变化,修改后UI自动刷新。
  • 用@Binding传递模型的绑定关系,修改Toggle时直接同步原数组中的模型属性,无需手动调用更新方法。
  • 首页面用ForEach($dataStore.dataSet)直接拿到每个元素的绑定,简化传递逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:57:28