SwiftUI颜色游戏校验失效求助:@State变量未更新及数组匹配问题
解决颜色记忆游戏的校验失效与@State更新问题
我帮你排查出了几个核心问题,咱们一步步来修复:
问题1:按钮索引匹配逻辑完全错误
你的input数组初始化是[1,2,3,4,5,6],但colors数组的索引是从0到5的(绿色对应0、红色对应1,依此类推)。更关键的是,每个按钮的校验逻辑错误地用了input[self.count2],这完全没对应到按钮本身的颜色索引,导致校验永远不会正确触发。
问题2:Timer线程导致@State更新不生效
用Timer.scheduledTimer创建的定时器默认在后台线程运行,直接修改@State变量可能无法触发SwiftUI视图刷新——因为@State的更新必须在主线程执行。
问题3:分数逻辑不一致
只有红色按钮的点击会增加分数,其他按钮没有这个逻辑,导致分数计算完全混乱。
修改后的完整代码
import SwiftUI struct ContentView: View { private let colors = [Color.green, Color.red, Color.blue, Color.pink, Color.orange, Color.purple] @State private var currentColor = Color.gray @State private var colorSequence = [Int]() // 重命名变量,更清晰表达用途:存储随机颜色索引序列 @State private var currentStep = 0 // 当前需要校验的序列步骤索引 @State private var score = 0 @State private var isShowingSequence = false // 标记是否正在展示颜色序列 // 生成随机颜色序列并开始展示 func startNewRound() { colorSequence = Array(repeating: 0, count: 6).map { _ in Int.random(in: 0...5) } currentStep = 0 isShowingSequence = true showNextColor(index: 0) } // 递归展示颜色序列(确保在主线程更新UI) func showNextColor(index: Int) { guard index < colorSequence.count else { isShowingSequence = false return } currentColor = colors[colorSequence[index]] DispatchQueue.main.asyncAfter(deadline: .now() + 1) { showNextColor(index: index + 1) } } // 处理颜色按钮点击的校验逻辑 func onColorTap(_ colorIndex: Int) { guard !isShowingSequence else { return } // 展示序列时禁止点击按钮 if colorIndex == colorSequence[currentStep] { currentStep += 1 score += 1 // 完成一轮校验后,自动开启下一轮 if currentStep == colorSequence.count { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { startNewRound() } } } else { // 错误时重置分数和步骤 score = 0 currentStep = 0 } } var body: some View { VStack{ Spacer() // 颜色展示区 Rectangle() .foregroundColor(currentColor) .frame(height: 150) .cornerRadius(10) .padding() Spacer() HStack{ Button(action: startNewRound) { Text("Start") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } .disabled(isShowingSequence) // 展示序列时禁用Start按钮 Text("步骤: \(currentStep + 1)/6") .font(.headline) Text("分数: \(score)") .font(.headline) .foregroundColor(.green) } .padding() Spacer() // 颜色按钮区 VStack(spacing: 16) { HStack(spacing: 16) { ColorButton(color: colors[0], action: { onColorTap(0) }) ColorButton(color: colors[1], action: { onColorTap(1) }) ColorButton(color: colors[2], action: { onColorTap(2) }) } HStack(spacing: 16) { ColorButton(color: colors[3], action: { onColorTap(3) }) ColorButton(color: colors[4], action: { onColorTap(4) }) ColorButton(color: colors[5], action: { onColorTap(5) }) } } .padding() } .padding() } } // 提取颜色按钮为子视图,减少代码重复 struct ColorButton: View { let color: Color let action: () -> Void var body: some View { Button(action: action) { Rectangle() .foregroundColor(color) .frame(width: 80, height: 80) .cornerRadius(12) .shadow(radius: 4) } .disabled(ContentView().isShowingSequence) // 展示序列时禁用所有颜色按钮 } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键修改说明
- 修复核心校验逻辑:每个颜色按钮点击时传递自己对应的索引(0-5),直接和
colorSequence[currentStep]对比,终于能正确校验顺序。 - 主线程更新UI:用
DispatchQueue.main.asyncAfter替代后台Timer,确保@State变量在主线程更新,视图能及时响应变化。 - 统一分数逻辑:所有正确点击都会加分,错误点击直接重置分数和步骤,逻辑一致。
- 用户体验优化:展示序列时禁用所有交互按钮,防止误操作;完成一轮后自动开启下一轮;优化了按钮样式和布局,视觉效果更友好。
- 代码结构优化:提取颜色按钮为子视图,减少重复代码,后续维护更方便;重命名变量让代码可读性大幅提升。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

