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

SwiftUI中修改@State数组内结构体属性无法更新UI的问题

SwiftUI中@State数组元素修改后不更新的解决方案

问题本质

你的代码存在两个核心问题:

  1. 结构体值类型特性导致修改无效:Item是结构体,直接通过items[$0].value = value修改时,items[$0]返回的是原元素的拷贝,修改的是拷贝而非原数组中的元素,原数组根本没变化。
  2. 类的错误使用方式:改成类后仍用@State修饰数组,但Swift中数组是值类型,修改类实例的属性不会改变数组的引用,@State无法感知内部变化,自然不会触发UI更新。

解决方案

方案1:保持Item为结构体,正确修改数组元素

要修改结构体数组中的元素,必须替换原位置的元素(让@State感知到数组值的变化):

struct Item: Codable, Identifiable {
    var id: Int
    var value: Int
}

struct ContentView: View {
    // 初始化时添加测试元素,否则点击按钮找不到id=1的元素
    @State private var items: [Item] = [Item(id: 1, value: 0)]

    var body: some View {
        NavigationStack {
            List {
                ForEach(items) { item in
                    Text("当前值:\(item.value)")
                }
            }
            Button("修改值为100", action: {
                updateValueOfItem(id: 1, value: 100)
            })
         }
    }

    func updateValueOfItem(id: Int, value: Int) {
        // 找到目标元素的索引
        guard let index = items.firstIndex(where: { $0.id == id }) else { return }
        // 创建新的Item替换原位置,触发@State感知数组变化
        items[index] = Item(id: id, value: value)
        print("array = \(items)") // 现在会输出更新后的值
    }
}

方案2:将Item改为类,配合ObservableObject使用

如果需要用类,必须让Item遵循ObservableObject并通过@Published标记可变属性,同时把数组放在ViewModel中管理:

import Combine

class Item: ObservableObject, Identifiable, Codable {
    var id: Int
    @Published var value: Int
    
    // Codable协议需要手动实现编码解码(处理@Published属性包装器)
    enum CodingKeys: String, CodingKey {
        case id, value
    }
    
    init(id: Int, value: Int) {
        self.id = id
        self.value = value
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(value, forKey: .value)
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        value = try container.decode(Int.self, forKey: .value)
    }
}

class ViewModel: ObservableObject {
    @Published var items: [Item] = [Item(id: 1, value: 0)]
    
    func updateValueOfItem(id: Int, value: Int) {
        guard let targetItem = items.first(where: { $0.id == id }) else { return }
        targetItem.value = value
        print("array = \(items)")
    }
}

struct ContentView: View {
    @StateObject private var viewModel = ViewModel()

    var body: some View {
        NavigationStack {
            List {
                ForEach(viewModel.items) { item in
                    Text("当前值:\(item.value)")
                }
            }
            Button("修改值为100", action: {
                viewModel.updateValueOfItem(id: 1, value: 100)
            })
         }
    }
}

关键说明

  • 结构体数组:必须通过替换元素让@State感知到数组值的变化,直接修改拷贝的属性无效。
  • 类数组:需要借助ObservableObject和@Published来发布属性变化通知,让SwiftUI触发UI更新,不能直接用@State修饰类数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:13:21