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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:42:33