Swift iPhone投注应用:while循环中按钮显示与输入等待问题
Swift iOS 人机对战投注功能实现问题
我正在为iPhone开发基于Swift语言的人机对战投注功能,采用while循环处理投注轮次,遍历所有玩家:若为电脑玩家,则调用自动投注函数;若为人类玩家,需显示投注、过牌、弃牌等操作按钮,并等待用户输入后再推进循环。但目前出现两个问题:
- 按钮始终无法显示(尽管隐藏操作后的打印语句可正常输出)
- 循环未等待用户输入便继续执行
请问实现该需求的正确结构是什么?
代码示例
listOfPlayers = [computer1, player1, computer2] while !bettingRoundComplete { for player in listOfPlayers { if player == computer1 { autoBet() } if player == player1 { betButton.isHidden = false checkButton.isHidden = false var playerFinishedTurn = false while !playerFinishedTurn { // 等待用户通过按钮输入(按钮本该显示但实际没显示) // 处理输入逻辑 // 将playerFinishedTurn设为true } if player == computer2 { autoBet() } // 若投注轮次结束,退出循环(全局变量flag由投注函数执行时触发) } }
问题根源
你现在的写法是阻塞式同步循环,而iOS的UI更新、用户交互都依赖主线程的RunLoop调度。你的while循环会持续占用主线程,导致RunLoop无法处理UI刷新(按钮显示)和用户点击事件,最终出现按钮不显示、循环不等待的问题。
正确实现方案:状态机+异步回调
放弃循环轮询的思路,改用状态驱动+按钮回调的方式管理投注流程,这是iOS处理用户交互的标准模式。
步骤1:定义核心状态变量
用变量追踪当前轮次的状态和玩家顺序:
var currentPlayerIndex = 0 let listOfPlayers: [Player] = [computer1, player1, computer2] var bettingRoundComplete = false
步骤2:封装单玩家回合处理逻辑
写一个函数统一处理当前玩家的回合,根据玩家类型分支执行:
func processCurrentPlayerTurn() { guard !bettingRoundComplete, currentPlayerIndex < listOfPlayers.count else { endBettingRound() return } let currentPlayer = listOfPlayers[currentPlayerIndex] if currentPlayer.isComputer { // 电脑玩家:自动投注完成后推进到下一位 autoBet(for: currentPlayer) { [weak self] in self?.moveToNextPlayer() } } else { // 人类玩家:显示操作按钮,绑定点击回调 betButton.isHidden = false checkButton.isHidden = false betButton.addTarget(self, action: #selector(betTapped), for: .touchUpInside) checkButton.addTarget(self, action: #selector(checkTapped), for: .touchUpInside) } }
步骤3:实现按钮回调与流程推进
处理用户点击事件,完成操作后隐藏按钮并推进到下一位玩家:
@objc func betTapped() { // 执行玩家投注逻辑 handlePlayerBet() cleanUpPlayerTurn() moveToNextPlayer() } @objc func checkTapped() { // 执行玩家过牌逻辑 handlePlayerCheck() cleanUpPlayerTurn() moveToNextPlayer() } func cleanUpPlayerTurn() { // 隐藏按钮并解绑回调,避免重复触发 betButton.isHidden = true checkButton.isHidden = true betButton.removeTarget(self, action: #selector(betTapped), for: .touchUpInside) checkButton.removeTarget(self, action: #selector(checkTapped), for: .touchUpInside) } func moveToNextPlayer() { currentPlayerIndex += 1 // 一轮遍历结束后,判断是否开启下一轮或结束投注 if currentPlayerIndex >= listOfPlayers.count { currentPlayerIndex = 0 if shouldEndBettingRound() { bettingRoundComplete = true } } // 处理下一位玩家的回合 processCurrentPlayerTurn() }
步骤4:启动投注轮次
在需要开始投注的时机调用:
currentPlayerIndex = 0 bettingRoundComplete = false processCurrentPlayerTurn()
关键注意点
- 绝对不要在主线程用while循环等待用户输入,会直接卡死UI
- 用状态变量追踪流程,而非循环轮询
- 依赖按钮回调触发流程推进,符合iOS异步交互逻辑
- 用户操作后务必解绑按钮回调,防止重复触发
内容的提问来源于stack exchange,提问作者Andrew Wertheim
相关产品推荐
相关产品推荐

