繁体   English   中英

UICollisionBehavior和UIGravityBehavior无法与DispatchQueue一起正常工作

[英]UICollisionBehavior and UIGravityBehavior not working as expected with DispatchQueue

我目前正在为一个已设计为可玩connect 4的框架设计UI。该框架封装在一个名为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()的第二次调用中添加的两张光盘。 这些不倒。

不管我尝试了什么

任何反馈都非常感谢!

后台线程很难,并且仅在绝对必要时才使用(因为它被强加于您,或者因为您执行一项耗时的活动并且您不想冻结该主线程拥有的接口) )。 这里似乎没有必要。 您没有做任何耗时的事情。 看起来使用DispatchQueue.global可能会使您感到困惑; 后台调度队列会导致您的代码乱序运行,显然您并不知道这一点。

解决方案:删除所有DispatchQueue.globalDispatchQueue.main代码。 (换句话说,消除这些行并匹配正确的大括号行。)然后,所有内容将只在主队列上运行,没有理由不这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM