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

SwiftUI随机颜色棋盘视图无法编译问题求助

问题根源

你这代码的问题出在直接在视图的body里生成随机颜色。SwiftUI的body是会被反复计算的,每次视图刷新时,[Color.green, ...].randomElement()!都会生成新的随机值,这又会触发视图再次刷新,陷入无限循环,最后就导致Xcode编译超时了。

解决办法

提前一次性生成所有棋盘格的随机颜色,存在固定数组里,别让它每次刷新都重新生成。给你两种方案:

方案1:初始化时生成固定颜色(一次性生成,不会变)

struct ChessBoard: View {
    let rows    : Int = 8
    let columns : Int = 8
    let squareSize: CGFloat
    @Binding var lastTappedSquareID: Int?
    // 提前存好所有格子的颜色
    private let squareColors: [Color]
    
    init(squareSize: CGFloat, lastTappedSquareID: Binding<Int?>) {
        self.squareSize = squareSize
        self._lastTappedSquareID = lastTappedSquareID
        let colorList = [Color.green, Color.blue, Color.brown, Color.darkGray]
        // 生成64个随机颜色(8x8)
        self.squareColors = (0..<rows*columns).map { _ in
            colorList.randomElement()!
        }
    }
    
    var body: some View {
        VStack(spacing: 0) {
            ForEach(0..<rows) { row in
                HStack(spacing: 0) {
                    ForEach(0..<columns) { column in
                        let id = row * columns + column + 1
                        let colorIndex = row * columns + column
                        Rectangle()
                            .fill(squareColors[colorIndex])
                            .frame(width: squareSize, height: squareSize)
                            .id(id)
                            .border(id == lastTappedSquareID ? .red : .clear, width: 3)
                            .onTapGesture {
                                lastTappedSquareID = id
                            }
                    }
                }
            }
        }
    }
}

方案2:用@State存颜色(支持后续重新生成)

如果之后想加个按钮重新生成随机颜色,就用@State来存数组,只有主动修改数组时才会刷新视图:

struct ChessBoard: View {
    let rows    : Int = 8
    let columns : Int = 8
    let squareSize: CGFloat
    @Binding var lastTappedSquareID: Int?
    @State private var squareColors: [Color] = []
    
    private let colorList = [Color.green, Color.blue, Color.brown, Color.darkGray]
    
    var body: some View {
        VStack(spacing: 0) {
            // 可选:加个按钮重新生成颜色
            Button("重新生成颜色") {
                squareColors = (0..<rows*columns).map { _ in
                    colorList.randomElement()!
                }
            }
            
            VStack(spacing: 0) {
                ForEach(0..<rows) { row in
                    HStack(spacing: 0) {
                        ForEach(0..<columns) { column in
                            let id = row * columns + column + 1
                            let colorIndex = row * columns + column
                            Rectangle()
                                .fill(squareColors[colorIndex])
                                .frame(width: squareSize, height: squareSize)
                                .id(id)
                                .border(id == lastTappedSquareID ? .red : .clear, width: 3)
                                .onTapGesture {
                                    lastTappedSquareID = id
                                }
                        }
                    }
                }
            }
        }
        .onAppear {
            // 视图加载时生成初始颜色
            squareColors = (0..<rows*columns).map { _ in
                colorList.randomElement()!
            }
        }
    }
}
为啥之前两种颜色的方案能跑?

因为(row + column) % 2 == 0 ? Color.green : Color.blue是固定逻辑,给定row和column,结果是确定的,不会每次刷新都变,所以不会触发无限循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:09:26