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

SwiftUI中模型变更时如何更新子视图?MVVM场景问题排查

SwiftUI MVVM嵌套Model状态切换与视图更新问题修复

问题根源

  1. 颜色未与状态绑定:Seats类中color仅在初始化时设置,后续isSelected状态变化时没有同步更新颜色,导致点击按钮后颜色不变化。
  2. 未监听单个实例变化:子视图使用@Binding数组,但未监听单个Seats实例的@Published属性变化,状态更新后视图无法自动刷新。
  3. ForEach标识不当:使用数组offset作为ForEach的id,易引发视图复用问题,且无法精准触发单个元素的更新。

修复方案

1. 调整Seats类,绑定状态与颜色

给isSelected添加didSet监听,状态变化时自动更新color,确保颜色与选中状态实时同步:

class Seats : ObservableObject, Codable, Identifiable {
    let id = UUID()
    let seatType : String?
    let status : Int?
    @Published var color: Color = Color.gray
    
    @Published var isSelected = false {
        didSet {
            color = isSelected ? .blue : .gray
        }
    }
    
    func toggleIsSelectedStatus() {
        isSelected = !isSelected
    }

    enum CodingKeys: String, CodingKey {
        case seatType = "seatType"
        case status = "status"
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        seatType = try values.decodeIfPresent(String.self, forKey: .seatType)
        status = try values.decodeIfPresent(Int.self, forKey: .status)
        
        color = isSelected ? .blue : .gray
    }
}

2. 修改子视图,实现局部更新

使用@ObservedObject监听单个Seats实例,ForEach直接使用实例自身的id作为标识,确保仅更新点击的按钮:

struct GateSectionView: View {
    @Binding var data:[Seats]
    private let adaptiveColumns = [
        GridItem(.adaptive(minimum: 30))
    ]
    
    var body: some View {
        VStack(spacing: 0) {
            LazyVGrid(columns: adaptiveColumns) {
                ForEach(data) { seat in
                    @ObservedObject var observedSeat = seat
                    Button {
                        observedSeat.toggleIsSelectedStatus()
                    } label: {
                        Text("\(data.firstIndex(of: seat)! + 1)")
                            .font(.system(size: 10, weight: .bold))
                            .frame(width: 25, height: 25)
                            .foregroundColor(.white)
                    }
                    .background(observedSeat.color)
                    .cornerRadius(3)
                }
            }.padding(10)
            Spacer()
        }
        .cornerRadius(12)
        .frame(width: 780)
    }
}

3. 清理父视图冗余代码

移除未使用的@State var setas = [Seats](),简化结构:

struct SeatSelectionView: View {
    @StateObject var seatLayoutViewModel = SeatLayoutViewModel()
    
    var body: some View {
        ZStack {
            Color.white
            ScrollView(.horizontal) {
                VStack(spacing: -5) {
                    HStack {
                        GateSectionView(data: $seatLayoutViewModel.totalSeats)
                            .frame(width: 780)
                    }
                    .padding(.top, 10)
                    .padding(.horizontal, 5)
                }
                .padding(.horizontal, 8)
                .padding(.bottom)
            }
        }
        .onAppear {
            seatLayoutViewModel.getSeatMasterData()
        }
    }
}

修复效果

点击按钮时,对应Seats实例的isSelected状态切换,color自动更新,@ObservedObject触发单个按钮视图刷新,实现仅更新点击的按钮,符合局部更新的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:55:04