首页 > 解决方案 > 如何强制在 Swift 中更新 UI?

问题描述

我正在使用 swift 开发国际象棋游戏。当计算机自己玩时,移动完成后显示不会更新,直到它退出循环(在这种情况下游戏结束)。

我试图在后台队列中调度它以生成移动并将其调度回主队列以进行移动并更新显示。虽然这似乎有助于更新显示,但我无法预测每个后台队列的完成情况。这打乱了动作的顺序。

有没有更好的方法让电脑自动播放并在每次移动完成后正确更新显示?

while chessGame.checkmate != true {
    DispatchQueue.global(qos: .background).async {
        let bestMove = chessAI.findBestMove(depth : chessGame.searchDepth)
        if bestMove != nil {
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
                chessMove.makeMove(m : bestMove!)
                self.boardView.setNeedsDisplay()
            }
        } else {
            print("CheckMate!")
            chessGame.checkmate = true
        }
    }
}

标签: multithreadinguser-interfaceswift3thread-safetydispatch

解决方案


可以立即强制显示(通过调用displayIfNeeded),但这无济于事。

问题是while循环不会在迭代之间暂停:它只是保持以最高速度循环。因此,while循环是一个糟糕的策略。

相反,使用递归。这使您可以控制何时进行下一次迭代,即延迟后递归。这是一个循环,您可以在迭代之间暂停。

伪代码:

func nextMove() {
    DispatchQueue.global(qos: .background).async {
        let bestMove = chessAI.findBestMove(depth : chessGame.searchDepth)
        if bestMove != nil {
            DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // or whatever
                chessMove.makeMove(m : bestMove!)
                self.boardView.setNeedsDisplay()
                if chessGame.checkmate != true {
                    nextMove()
                } else {
                    print("checkmate")
                }
            }
        }
    }
}

推荐阅读