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

SwiftUI添加列表行后View组件未更新问题求助

SwiftUI点击添加按钮后SetsRowView不新增的解决方案

核心问题分析

你当前的ExerciseCardViewModel中,@Published var exercise: Exercise仅会在exercise实例本身被替换时触发视图更新。但你修改的是exercise内部的sets数组(若Exercise为类类型),这种内部属性的变化不会触发@Published的通知,导致视图无法感知数组变更。

解决方案

方案1:让Exercise成为ObservableObject(推荐)

将Exercise类改为遵循ObservableObject,并把sets标记为@Published,这样内部数组的变化会自动通知视图:

class Exercise: ObservableObject {
    @Published var sets: [DBSet] = []
    // 你的其他Exercise属性(如名称、类型等)
}

然后修改ExerciseCardViewModel,将exercise改为@ObservedObject:

class ExerciseCardViewModel: ObservableObject {
    @ObservedObject var exercise: Exercise
    
    init(exercise: Exercise) {
        self.exercise = exercise
    }
    
    func addSet() {
        exercise.sets.append(DBSet(number: exercise.sets.count + 1))
    }
    
    func deleteSet() {
        exercise.sets.removeLast()
    }
    
    func createSetViewModel(sets: DBSet) -> SetViewModel {
        SetViewModel(sets: sets)
    }
}

调用addSet()修改sets数组时,Exercise的@Published会自动发送更新通知,视图会重新渲染新增行。

方案2:手动触发ViewModel的更新通知

如果不想修改Exercise的结构,可在修改sets数组后手动调用objectWillChange.send()通知视图更新:

class ExerciseCardViewModel: ObservableObject {
    @Published var exercise: Exercise
    
    init(exercise: Exercise) {
        self.exercise = exercise
    }
    
    func addSet() {
        exercise.sets.append(DBSet(number: exercise.sets.count + 1))
        objectWillChange.send()
    }
    
    func deleteSet() {
        exercise.sets.removeLast()
        objectWillChange.send()
    }
    
    func createSetViewModel(sets: DBSet) -> SetViewModel {
        SetViewModel(sets: sets)
    }
}

额外检查项

  • 确保DBSet遵循Identifiable协议,或在ForEach中明确指定id参数,否则SwiftUI无法识别数组元素变化:
    ForEach(viewModel.exercise.sets, id: \.id) { set in
        SetsRowView(sets: viewModel.createSetViewModel(sets: set))
            .listRowBackground(Color.theme.TBBlack)
    }
    
    (假设DBSet有唯一属性id)
  • 确认父视图中ExerciseCard的viewModel通过@StateObject创建,保证实例唯一性:
    // 父视图示例代码
    @StateObject private var exerciseVM = ExerciseCardViewModel(exercise: Exercise())
    
    var body: some View {
        ExerciseCard(viewModel: exerciseVM, deleteExercise: { _ in })
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:35:03