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

Swift中无法修改Struct内Bool变量的问题解惑

问题原因
  • Swift 中的 Struct 是值类型,当你在 List 里遍历 newspaperRegion 的元素时,拿到的 newspaper 是一个不可变的 let 常量副本。值类型的副本默认无法修改,因此调用需要改变自身状态的 mutating 方法时就会触发报错。
  • 即便用全局变量存储数据,遍历得到的依然是独立的副本,直接修改副本不会影响原全局变量,且副本本身是 let 常量,无法调用 mutating 方法。

解决方案

方案1:通过索引定位原数据修改

利用遍历的索引直接修改全局变量里的原元素,绕过副本不可变的限制:

struct SettingsView: View {
    var body: some View {
        List {
            // 遍历地区并拿到索引
            ForEach(Array(newspaperRegion.enumerated()), id: \.element.id) { regionIndex, region in
                Section(header: Text(region.name)) {
                    // 遍历该地区的报纸并拿到索引
                    ForEach(Array(region.newspapers.enumerated()), id: \.element.id) { paperIndex, newspaper in
                        HStack {
                            Text(newspaper.name)
                            Spacer()
                            Button(action: {
                                // 通过索引直接修改全局变量中的原数据
                                newspaperRegion[regionIndex].newspapers[paperIndex].changeFavorite()
                            }) {
                                Image(systemName: newspaper.favorite ? "star.fill" : "star")
                            }
                        }
                    }
                }
            }
        }
    }
}

方案2:将结构体改为引用类型(Class)

把 Newspaper 和 NewspaperRegion 改为 Class(引用类型),此时遍历拿到的是对象的引用,即使引用本身是 let 常量,也可以修改对象内部的属性:

class Newspaper: Identifiable {
    let id = UUID()
    var name: String
    var favorite: Bool
    
    init(name: String, favorite: Bool) {
        self.name = name
        self.favorite = favorite
    }
    
    // 无需mutating修饰,类方法可直接修改属性
    func changeFavorite() {
        favorite.toggle()
    }
}

class NewspaperRegion: Identifiable {
    let id = UUID()
    var name: String
    var newspapers: [Newspaper]
    
    init(name: String, newspapers: [Newspaper]) {
        self.name = name
        self.newspapers = newspapers
    }
}

// 全局变量
var newspaperRegion: [NewspaperRegion] = [
    NewspaperRegion(name: "北京", newspapers: [Newspaper(name: "北京日报", favorite: false)])
]

struct SettingsView: View {
    var body: some View {
        List {
            ForEach(newspaperRegion) { region in
                Section(header: Text(region.name)) {
                    ForEach(region.newspapers) { newspaper in
                        HStack {
                            Text(newspaper.name)
                            Spacer()
                            Button(action: {
                                newspaper.changeFavorite()
                            }) {
                                Image(systemName: newspaper.favorite ? "star.fill" : "star")
                            }
                        }
                    }
                }
            }
        }
    }
}

方案3:用SwiftUI状态管理(推荐)

全局变量不是SwiftUI的最佳实践,推荐用 @StateObject + @Published 管理数据,确保数据变化时视图自动刷新:

// 保持原结构体定义不变
struct Newspaper: Identifiable {
    let id = UUID()
    var name: String
    var favorite: Bool
    
    mutating func changeFavorite() {
        favorite.toggle()
    }
}

struct NewspaperRegion: Identifiable {
    let id = UUID()
    var name: String
    var newspapers: [Newspaper]
}

// 用ObservableObject封装数据
class NewspaperData: ObservableObject {
    @Published var regions: [NewspaperRegion] = [
        NewspaperRegion(name: "北京", newspapers: [Newspaper(name: "北京日报", favorite: false)])
    ]
}

struct SettingsView: View {
    @StateObject private var newspaperData = NewspaperData()
    
    var body: some View {
        List {
            // 用$绑定可变的地区对象
            ForEach($newspaperData.regions) { $region in
                Section(header: Text(region.name)) {
                    // 用$绑定可变的报纸对象
                    ForEach($region.newspapers) { $newspaper in
                        HStack {
                            Text(newspaper.name)
                            Spacer()
                            Button(action: {
                                newspaper.changeFavorite()
                            }) {
                                Image(systemName: newspaper.favorite ? "star.fill" : "star")
                            }
                        }
                    }
                }
            }
        }
    }
}

这里的 $ 符号代表可变绑定,让 newspaper 变为可修改状态,同时 @Published 会自动触发视图刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:27:55