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

SwiftUI:如何在ForEach循环表格中持久化更新变量值

SwiftUI中如何让状态变量在列表行间保留值

给定的SwiftUI代码中,currentColumn作为@State变量,在List渲染每一行时会被重置为初始值0,无法保留上一行更新后的状态,导致后续行无法进入正确的条件分支。

问题根源

  1. lastUpwardTrend是columnToShowNumber函数的局部变量,每次调用函数都会重新初始化,无法跟踪上一行的数值。
  2. 直接在List行的渲染逻辑中修改@State变量,会触发视图重绘,导致状态更新和渲染逻辑相互干扰,无法保证状态连续性。

解决方案

方案一:将跟踪变量改为视图状态

把lastUpwardTrend也声明为@State变量,让它和currentColumn一起在视图生命周期中保留状态,调整逻辑确保状态连贯:

import SwiftUI

struct ContentView: View {
    let numbers: [Double] = [
        10.0, 50.0, 150.0, 80.0, 30.0, 120.0, 70.0, 20.0, 180.0, 40.0,
        100.0, 60.0, 90.0, 130.0, 170.0, 110.0, 160.0, 140.0, 190.0, 200.0,
        170.0, 30.0, 50.0, 90.0, 120.0, 10.0, 180.0, 70.0, 150.0, 20.0,
        40.0, 110.0, 80.0, 60.0, 140.0, 100.0, 200.0, 130.0, 190.0, 160.0,
        30.0, 150.0, 80.0, 40.0, 120.0, 70.0, 180.0, 110.0, 50.0, 20.0
    ]
    
    let numberOfColumns = 6
    
    // 声明状态变量存储当前列和上一个上升趋势值
    @State var currentColumn = 0
    @State var lastUpwardTrend: Double?
    
    var body: some View {
        List(numbers.indices, id: \.self) { index in
            TableRowView(number: numbers[index], column: columnToShowNumber(numbers[index]))
        }
    }
    
    func columnToShowNumber(_ number: Double) -> Int? {
        if currentColumn == 0 {
            currentColumn = 2
            lastUpwardTrend = number
            print("currentColumn starts at Upward Trend column successfully:", currentColumn,", lastUpwardTrend:", lastUpwardTrend! )
            return 2
        }
        
        if currentColumn == 2 && lastUpwardTrend != nil {
            if number > lastUpwardTrend! {
                lastUpwardTrend = number
                return 2
            }
            // 可添加趋势变化时的其他分支逻辑
        }
        
        return nil
    }
}

struct TableRowView: View {
    let number: Double
    let column: Int?
    
    var body: some View {
        HStack {
            ForEach(0..<6) { columnIndex in
                if columnIndex == column {
                    Text("\(number)")
                        .frame(width: 100, height: 50)
                        .border(Color.gray)
                } else {
                    Spacer()
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键改动:

  • 将lastUpwardTrend从函数局部变量改为@State变量,确保其在视图生命周期中保留值。
  • 增加lastUpwardTrend != nil的空值判断,避免崩溃。

方案二:提前预处理数据(更稳定)

如果不需要动态修改状态,建议在视图初始化时直接预处理所有数字对应的列,避免渲染时的状态干扰:

import SwiftUI

struct ContentView: View {
    let numbers: [Double] = [
        10.0, 50.0, 150.0, 80.0, 30.0, 120.0, 70.0, 20.0, 180.0, 40.0,
        100.0, 60.0, 90.0, 130.0, 170.0, 110.0, 160.0, 140.0, 190.0, 200.0,
        170.0, 30.0, 50.0, 90.0, 120.0, 10.0, 180.0, 70.0, 150.0, 20.0,
        40.0, 110.0, 80.0, 60.0, 140.0, 100.0, 200.0, 130.0, 190.0, 160.0,
        30.0, 150.0, 80.0, 40.0, 120.0, 70.0, 180.0, 110.0, 50.0, 20.0
    ]
    
    let numberOfColumns = 6
    // 预处理好每个数字对应的列
    private var numberColumns: [Int?]
    
    init() {
        var currentColumn = 0
        var lastUpwardTrend: Double?
        self.numberColumns = numbers.map { number in
            var result: Int? = nil
            if currentColumn == 0 {
                currentColumn = 2
                lastUpwardTrend = number
                result = 2
            } else if currentColumn == 2 && lastUpwardTrend != nil {
                if number > lastUpwardTrend! {
                    lastUpwardTrend = number
                    result = 2
                }
            }
            return result
        }
    }
    
    var body: some View {
        List(numbers.indices, id: \.self) { index in
            TableRowView(number: numbers[index], column: numberColumns[index])
        }
    }
}

struct TableRowView: View {
    let number: Double
    let column: Int?
    
    var body: some View {
        HStack {
            ForEach(0..<6) { columnIndex in
                if columnIndex == column {
                    Text("\(number)")
                        .frame(width: 100, height: 50)
                        .border(Color.gray)
                } else {
                    Spacer()
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

优势:

  • 状态计算仅在初始化时执行一次,避免List渲染时的状态修改和重绘干扰。
  • 渲染逻辑更纯粹,仅负责展示预处理数据,性能更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:17:03