Swift GameKit:与插件的连接在使用中中断

Swift GameKit:与插件的连接在使用中中断,swift,gamekit,Swift,Gamekit,我已经试着解决这个问题好几个星期了。苹果开发者论坛没有回应。苹果开发人员的技术支持没有真正的帮助。考虑到我的项目中出现问题的可能性很高,我不能相信没有人解决过这个问题。无论如何,这是我的GameKitManager类: final class GameCenterManager : NSObject, GKLocalPlayerListener { static let manager = GameCenterManager() weak var delegate: G

我已经试着解决这个问题好几个星期了。苹果开发者论坛没有回应。苹果开发人员的技术支持没有真正的帮助。考虑到我的项目中出现问题的可能性很高,我不能相信没有人解决过这个问题。无论如何,这是我的GameKitManager类:

final class GameCenterManager : NSObject, GKLocalPlayerListener {
    
    static let manager = GameCenterManager()
    weak var delegate: GameCenterManagerDelegate?
    var gameCenterViewController: UIViewController?
    var match: GKMatch?
    static var isAuthenticated: Bool {
        return GKLocalPlayer.local.isAuthenticated
    }
    var matchmakerViewController: GKMatchmakerViewController?
    var invite: GKInvite?
    
    
    override init() {
        super.init()
    }

    func authenticatePlayer() {

        GKLocalPlayer.local.authenticateHandler = { gcAuthVC, error in
            
            self.delegate?.didChangeAuthStatus(isAuthenticated: GKLocalPlayer.local.isAuthenticated)

            if GKLocalPlayer.local.isAuthenticated {
                GKLocalPlayer.local.register(self)
            }
            // If the User needs to sign to the Game Center
            else if let vc = gcAuthVC {
                self.delegate?.presentGameCenterAuth(viewController: vc)
            }
            else {
                print(">>>>> Error authenticating the Player! \(error?.localizedDescription ?? "none") <<<<<")
            }
        }
    }
    

    func presentMatchmaker() {
        guard GKLocalPlayer.local.isAuthenticated else { return }
        
        let request = GKMatchRequest()
        request.minPlayers = 2
        request.maxPlayers = 4
        request.inviteMessage = "Would you like to play?"
        
        matchmakerViewController = GKMatchmakerViewController(matchRequest: request)
        matchmakerViewController!.matchmakerDelegate = self
        delegate?.presentMatchmaking(viewController: matchmakerViewController)
    }
    
    
    func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        self.invite = invite
        // Start match making 4 seconds after to let the invitation sliding menu to finish loading
        let seconds = 4.0
        DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
            self.makeMatchmakerVC(from: invite)
        }
    }
    
    
    func makeMatchmakerVC(from invite:GKInvite) {
        // Accepting invitation from GKMatchmakerViewController (Friends are displayed)
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: true, completion: {
                self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
                self.matchmakerViewController!.matchmakerDelegate = self
                self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
            })
        }
        // Accepting invitation when GKMatchmakerViewController is not yet presented
        else {
            guard let vc = GKMatchmakerViewController(invite: invite) else { return }
            self.matchmakerViewController = vc
            matchmakerViewController!.matchmakerDelegate = self
            delegate?.presentMatchmaking(viewController: matchmakerViewController!)
        }
    }
}


extension GameCenterManager: GKMatchmakerViewControllerDelegate {
    
    func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
        
        print("-----matchmakerVC did find match-------")
        
        viewController.dismiss(animated: true, completion: {
            self.match = match
            self.match!.delegate = self
            self.delegate?.presentGame(match: self.match!)
        })
    }
    

    func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
        viewController.dismiss(animated: true)
        delegate?.matchmakingCancelled()
    }
    

    func matchmakerViewController(_ viewController: GKMatchmakerViewController,
                                  didFailWithError error: Error)
    {
        
        viewController.dismiss(animated: true, completion: {

            print("################# fail with error ##################\n\(error.localizedDescription)\n")
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
            self.invite = nil
            self.match = nil
        })
    }
}
最终类GameCenterManager:NSObject,GKLocalPlayerListener{
静态let管理器=GameCenterManager()
弱var委托:GameCenterManagerDelegate?
var gameCenterViewController:UIViewController?
变量匹配:GKMatch?
静态变量已验证:Bool{
返回GKLocalPlayer.local.isAuthenticated
}
var matchmakerViewController:GKMatchmakerViewController?
var invite:GKIVITE?
重写init(){
super.init()
}
func authenticatePlayer(){
GKLocalPlayer.local.authenticateHandler={gcAuthVC,中出现错误
self.delegate?.didChangeAuthStatus(isAuthenticated:GKLocalPlayer.local.isAuthenticated)
如果GKLocalPlayer.local.isAuthenticated{
GKLocalPlayer.local.register(self)
}
//如果用户需要登录游戏中心
否则,如果让vc=gcAuthVC{
self.delegate?.presentGameCenterAuth(视图控制器:vc)
}
否则{

打印(“>>>验证播放器时出错!\”(错误?.localizedDescription???“无”)如果有人遇到相同的问题,以下操作是否有帮助

func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: false, completion: nil)
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
        }

        let delayTime = DispatchTime.now() + .milliseconds(2000)

        DispatchQueue.main.asyncAfter(deadline: delayTime) {
            self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
            self.matchmakerViewController!.matchmakerDelegate = self
            self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
        }
}
Dispatch.asyncAfter让系统有时间在开始新任务之前对matchmakerViewController进行全面“清理”。我现在正在测试它,但其他人的反馈将不胜感激

编辑: 经过更多的测试,这并不是解决方案;问题还在继续。但是,我注意到,当第二个玩家打开了GKMatchmakerViewController实例时,我没有问题。换句话说,如果我调用
presentMatchmaker()
首先,然后接受邀请,它会起作用。因此,例如,当第二个玩家不在游戏中并收到游戏邀请时,就会出现问题。因此,我将代码更改为以下代码,到目前为止似乎有效:

public func player(_ player: GKPlayer, didAccept invite: GKInvite) {
        if matchmakerViewController != nil {
            matchmakerViewController!.dismiss(animated: false, completion: nil)
            self.matchmakerViewController!.matchmakerDelegate = nil
            self.matchmakerViewController = nil
        }
        
        // THIS HELPS AVOID CRASH.
        presentMatchmaker()
        
        let delayTime = DispatchTime.now() + .milliseconds(1000)
        DispatchQueue.main.asyncAfter(deadline: delayTime) {
            self.matchmakerViewController = GKMatchmakerViewController(invite: invite)
            self.matchmakerViewController!.matchmakerDelegate = self
            self.delegate?.presentMatchmaking(viewController: self.matchmakerViewController!)
        }
    }

这不是一个非常优雅的解决方案…

当错误发生时,我发现了另一个用例。玩家1邀请玩家2玩游戏,玩家2接受邀请。然后任何一个玩家停止比赛(比赛被取消,现在两个都为零:
GameCenterManager.manager.match.disconnect();GameCenterManager.manager.match=nil
)。然后,玩家2邀请玩家1,玩家1接受另一场比赛的邀请。玩家2找到比赛并进入游戏场景,而玩家1最终出现此错误(接受邀请,然后无法创建新比赛)。如果其他人遇到此问题,我发现创建和显示
GKMatchmakerViewController
,然后在
DispatchQueue.main.asyncAfter(截止日期:.now())中设置委托
也解决了这个问题。这仍然是一个黑客攻击,但似乎更干净,因为不需要额外的视图控制器,也没有延迟。谢谢。正如您在我的最后一段代码中看到的,这就是我所做的。如果不调用
presentMatchmaker()
,仍然存在相同的问题。干杯。