UICollisionBehavior и UIGravityBehavior не работают должным образом с DispatchQueue - PullRequest
0 голосов
/ 14 апреля 2019

В настоящее время я разрабатываю пользовательский интерфейс для инфраструктуры, которую мне дали, которая играет в connect 4. Эта инфраструктура инкапсулирована в класс GameSession. Я не буду описывать тонкости его API и его работу. Я не верю, что это важно.

Я полагаю, что я неправильно понимаю очереди рассылки и неправильно их использую. Но я искал бесконечно и не нашел ничего, что указывало бы на решение моей проблемы.

Вот краткое объяснение происходящего. Метод, который контролирует ходы, это playGame (botStarts: Bool, atColumn: Int). В этом методе граница столкновения добавляется в правильной строке и столбце с помощью метода addBoundary (atRow: Int, atColumn: Int). Затем диск создается с помощью метода dropDisc (atColumn: Int, color: UIColor). Этот метод создает пользовательский UIView, добавляет его к представлению на экране и добавляет поведение при столкновении и гравитации. Он падает, пока не достигнет ранее добавленной границы.

В playGame () я сбрасываю диски на экран с помощью DispatchMain.Queue.async {dropDisc ()}. Но каждый раз, когда я вызываю playGame () во второй раз и далее, пользовательские диски рисуются в верхней части экрана, но они не падают. На первой итерации они рисуются и падают, как и ожидалось.

Ниже приведены функции, на которые я ссылался выше.

private func playGame(botStarts: Bool, dropPieceAt: Int) {
        DispatchQueue.global(qos: .userInitiated).async {
            if botStarts {
                if let move = gameSession.move {
                    let column = move.action % self.gameSession.boardLayout.columns
                    let row = move.action / self.gameSession.boardLayout.columns
                    self.addBoundary(atRow: row, atColumn: column)
                    DispatchQueue.main.async {
                        self.dropDisc(atColumn: column, color: move.color)
                    }
                }
            } else {
                let column = dropPieceAt
                if self.gameSession.userPlay(at: column) {
                    if let move = self.gameSession.move {
                        print(move)
                        let column = move.action % self.gameSession.boardLayout.columns
                        let row = move.action / self.gameSession.boardLayout.columns
                        self.addBoundary(atRow: row, atColumn: column)
                        DispatchQueue.main.async {
                            self.dropDisc(atColumn: column, color: move.color)
                        }
                    }
                    if let move = self.gameSession.move {
                        let column = move.action % self.gameSession.boardLayout.columns
                        let row = move.action / self.gameSession.boardLayout.columns
                        self.addBoundary(atRow: row, atColumn: column)
                        DispatchQueue.main.async {
                            self.dropDisc(atColumn: column, color: move.color)
                        }
                    }
                }
                if self.gameSession.done {
                    if let outcome = self.gameSession.outcome {
                        DispatchQueue.main.async {
                            self.gameLabel.text = outcome.message + "\n Winning pieces \(outcome.winningPieces)"
                        }
                    }
                }
            }
        }
    }


 private func dropDisc(atColumn: Int, color: UIColor) {
        var frame = CGRect()
        frame.origin = CGPoint.zero
        frame.size = Constants.bubbleSize
        let x = CGFloat(39) + CGFloat(47 * atColumn)
        frame.origin.x = x
        let bubbleView = DiscView(frame: frame, color: color)
        gameView.addSubview(bubbleView)
        collider.addItem(bubbleView)
        gravity.addItem(bubbleView)
    }



    // Adds a boundary using the row and column obtained from game session.
    private func addBoundary(atRow: Int, atColumn: Int) {
        let fromCoordX = CGFloat(16 + (boardView.initialX-boardView.radius)) + CGFloat(47 * atColumn)
        let toCoordX = fromCoordX + CGFloat(24)
        let coordY =  CGFloat(198.5 + (boardView.initialY+boardView.radius)) + CGFloat(45 * atRow)
        let fromPoint = CGPoint(x: fromCoordX, y: coordY+1)
        let toPoint = CGPoint(x: toCoordX, y: coordY+1)
        self.collider.addBoundary(withIdentifier: "boundary" as NSCopying, from: fromPoint, to: toPoint)
        self.drawLineFromPoint(start: fromPoint, toPoint: toPoint, ofColor: UIColor.red, inView: self.gameView)

    }

Вот скриншот моего экрана: https://imgur.com/7M3fklo.

В нижнем ряду вы видите диск пользователя (желтый) и диск ботов (красный). Они были добавлены при первом вызове playGame (). Но сверху вы можете увидеть два диска, которые были добавлены при втором вызове playGame (). Они не падают.

Что бы я ни пытался

Любая обратная связь очень ценится!

1 Ответ

1 голос
/ 14 апреля 2019

Фоновая многопоточность сложна и должна использоваться только тогда, когда это абсолютно необходимо (потому что она навязана вам, или потому что у вас есть трудоемкое действие, и вы не хотите останавливать интерфейс, который принадлежит основная нить). Это не кажется необходимым здесь. Вы не делаете ничего трудоемкого. И похоже, что использование DispatchQueue.global может сбить вас с толку; фоновая очередь отправки приводит к тому, что ваш код работает не по порядку, и, очевидно, вы не знали об этом.

Решение: просто избавьтесь от кода DispatchQueue.global и DispatchQueue.main. (Другими словами, удалите эти строки и сопоставьте правильные линии фигурных скобок.) Тогда все будет просто выполняться в главной очереди, и нет никаких причин, по которым это не следует делать.

...