Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/109.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在播放器按下其他视图控制器中的按钮之前关闭?_Ios_Swift_Delegates_Closures_Chess - Fatal编程技术网

Ios 如何在播放器按下其他视图控制器中的按钮之前关闭?

Ios 如何在播放器按下其他视图控制器中的按钮之前关闭?,ios,swift,delegates,closures,chess,Ios,Swift,Delegates,Closures,Chess,我正在用Swift 3编写一个国际象棋GUI,并用作国际象棋模型/库。现在,我面临着一个问题,一个圣人关闭用于作品推广 Sage(在其游戏类中)使用execute(move:promotion:)方法执行升级移动,该方法有一个返回升级块种类的闭包。这允许在选择促销商品种类之前提示用户选择促销商品或执行任何其他操作,如下所示: try game.execute(move: move) { ... return .queen } 我实现了一个升级视图控制器(“pvc”),在这个闭包

我正在用Swift 3编写一个国际象棋GUI,并用作国际象棋模型/库。现在,我面临着一个问题,一个圣人关闭用于作品推广

Sage(在其游戏类中)使用execute(move:promotion:)方法执行升级移动,该方法有一个返回升级块种类的闭包。这允许在选择促销商品种类之前提示用户选择促销商品或执行任何其他操作,如下所示:

try game.execute(move: move) {
    ...
    return .queen
}
我实现了一个升级视图控制器(“pvc”),在这个闭包中被称为,以便玩家可以选择新的作品:

// This is in the main View Controller class

/// The piece selected in promotionViewController into which a pawn shall promote
var newPiece: Piece.Kind = ._queen // default value = Queen

try game.execute(move: move) {
    boardView.isUserInteractionEnabled = false

    // promotionview controller appears to select new promoted piece
    let pvc = PromotionViewController(nibName: nil, bundle: nil)
    pvc.delegate = self
    pvc.modalPresentationStyle = .overCurrentContext
    self.present(pvc, animated:true)

    return newPiece
}
当按下pvc中新工件的按钮时,pvc将自行解除,所选工件的数据(常量selectedType)通过委派传输回主视图控制器:

// This is in the sending PVC class
protocol PromotionViewControllerDelegate {
    func processPromotion(selectedType: Piece.Kind)
}

func buttonPressed(sender: UIButton) {
    let selectedType = bla bla bla ...
    delegate?.processPromotion(selectedType: selectedType)
    presentingViewController!.dismiss(animated:true)
}


// This is in the receiving main View Controller class
extension GameViewController: PromotionViewControllerDelegate {

func processPromotion(selectedType: Piece.Kind) {
    defer {
        boardView.isUserInteractionEnabled = true
    }
    newPiece = selectedType
}
我遇到的问题是,闭包(在game.execute方法中)不会等到玩家在pvc中做出选择(并立即返回仍然是默认值的newPiece变量),这样我就不会得到除默认值之外的其他升级块

如何使关闭等待,直到播放器按下pvc中的按钮?

当然,我试图找到一个解决方案,并阅读了有关回调、完成处理程序或属性观察器的内容。我不知道哪条路是最好的,一些想法:

完成处理程序:pvc在发生按钮按下事件时自行解除,因此完成处理程序不在接收(主)视图控制器中。我该怎么处理

属性观察者:我只能在设置升级块(使用didset)后调用try game.execute(move)方法,但这会使代码难以阅读,并且无法使用game.execute方法提供的漂亮闭包


回调可能与完成处理程序有关,但不确定。

因此您在
游戏中的块。执行(移动:移动)
将完全执行Sage API设计的块。你不能简单地暂停它,但它是可行的,还是让我们试着用另一种方法来解决它

为什么需要在此块中调用视图控制器的表示?想尽一切办法把它移开。调用
try game.execute(move:move){
只能在
processPromotion
delegate方法中调用。您没有发布任何代码,但无论在哪里
try game.execute(move:move){
code都需要单独显示视图控制器来替换

然后在代理上,您甚至不需要保留值
newPiece=selectedType
,只需调用
try game.execute(move:move){return selectedType}

关于暂停块:

不可能直接“暂停”一个块,因为它是执行的一部分,这意味着整个操作需要暂停,这最终意味着您需要暂停整个线程。这意味着您需要将调用移动到一个单独的线程并暂停该线程。但是,这只有在API支持多线程时才有效,如果回调与它的线程在同一步调用e> 执行call…因此有很多工具和方法可以锁定线程,所以让我使用最原始的工具,使线程休眠:

    var executionLocked: Bool = false

    func foo() {
        DispatchQueue(label: "confiramtion queue").async {
            self.executionLocked = true
            game.execute(move: move) {
                // Assuming this is still on the "confiramtion queue" queue
                DispatchQueue.main.async {
                    // UI code needs to be executed on main thread
                    let pvc = PromotionViewController(nibName: nil, bundle: nil)
                    pvc.delegate = self
                    pvc.modalPresentationStyle = .overCurrentContext
                    self.present(pvc, animated:true)
                }
                while self.executionLocked {
                    Thread.sleep(forTimeInterval: 1.0/5.0) // Check 5 times per second if unlocked
                }
                return self.newPiece // Or whatever the code is
            }
        }
    }
现在,在您的代理中,您需要:

func processPromotion(selectedType: Piece.Kind) {
    defer {
        boardView.isUserInteractionEnabled = true
    }
    newPiece = selectedType
    self.executionLocked = false
}
因此,这里发生的事情是我们启动一个新线程。然后锁定执行并在
游戏
实例上开始执行。在块中,我们现在在主线程上执行代码,然后创建一个“无休止”循环,其中线程每次都会休眠一点(实际上并不需要休眠,但它可以防止循环占用太多CPU资源).现在所有的事情都发生在主线程上,即出现了一个新的控制器,用户可以使用它做一些事情…然后一旦完成,一个代理将解锁执行锁,这将使“无止境”循环退出(在另一个线程上),并将值返回到您的
游戏
实例

我不希望您实现这一点,但如果您随后确保采取所有预防措施,以便在需要时正确释放循环。例如,如果视图控制器被解除,则应解锁它,如果代理具有“取消”版本,则应退出