Search code examples
multithreadinguser-interfaceswift3thread-safetydispatch

How can I force UI updated in Swift?


I am using swift to develop a chess game. When the computer is playing itself, the display does not get updated when a move completed until it is out of the loop (in this case the game is ended).

I have tried to dispatch it in a background queue to generate a move and dispatch it back to main queue to make the move and update the display. While it seems to help updating the display, but I have no way to predict the completion of each background queue. That messes up the order of the moves.

Is there a better way to make computer playing itself and properly update the display after each move is completed?

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
        }
    }
}

Solution

  • You can force display immediately (by calling displayIfNeeded), but it won't help.

    The problem is that the while loop does not pause between iterations: it just keeps looping at top speed. Thus the while loop is a poor strategy.

    Instead, use recursion. This puts control of when to do the next iteration in your hands, namely, you recurse after a delay. That is a loop where you get to pause between iterations.

    Pseudocode:

    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")
                    }
                }
            }
        }
    }