UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Using coordinators to manage SwiftUI view controllers

Forums > 100 Days of SwiftUI

How do I inject GKMatch into SwiftUI view similar to this example https://www.hackingwithswift.com/books/ios-swiftui/using-coordinators-to-manage-swiftui-view-controllers ? I am building a multiplayer game in SwiftUI and I had to use UIViewControllerRepresentable to wrap the GKMatchMakerViewController into SwiftUI, however, I face a little problem where GKMatchDelegate methods are not being called. I have detected that it is happening because I dismiss the viewcontroller on didFindMatch method. I have tried to follow the above linked example, but I am not sure how I can put the GKMatch into a SwiftUI view as twoStraws did with the image in the example like so

func loadImage() {
    guard let inputImage = inputImage else { return }
    image = Image(uiImage: inputImage)
}

Can someone tell me what I can do? I tried my version like below.

func loadMatch() {
        guard let uImultiPlayerMatch = uImultiPlayerMatch else { return }
        multiPlayerMatch = uImultiPlayerMatch
    }

This is the code I have to load the GKMatch: multiPlayerMatch into my view but it doesn't solve my problem. Which view can take in the GKMatch type?

Below is how my wrapper struct looks like.

struct FinalMatchMaker: UIViewControllerRepresentable {

    @Binding var multiPlayerMatch: GKMatch?
    @Binding var dataModel: DataModel!
    let settings = AppSettings.sharedSettings

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> GKMatchmakerViewController {
        let request = GKMatchRequest()

        request.minPlayers = 2
        request.maxPlayers = 2
        request.inviteMessage = "Would you like to play Rock Paper Scissors?"

        let viewController = GKMatchmakerViewController(matchRequest: request)
        viewController?.matchmakerDelegate = context.coordinator

        return viewController!
    }

    func updateUIViewController(_ uiViewController: GKMatchmakerViewController, context: Context) {
        print("updateUIViewController")
    }

    func savePlayers() {
        guard let player2Name = multiPlayerMatch?.players.first?.displayName else { return }

        let playerOne = Player(displayName: GKLocalPlayer.local.displayName)
        let playerTwo = Player(displayName: player2Name)

        dataModel.players = [playerOne, playerTwo]
        dataModel.players.sort { (playerOne, playerTwo) -> Bool in
            playerOne.displayName < playerTwo.displayName
        }
        settings.playerOneDisplayName = playerOne.displayName
        settings.playerTwoDisplayName = playerTwo.displayName
        sendData()
    }

    func sendData() {
        guard let  match = multiPlayerMatch else { return }

        do {
            guard let data = dataModel.encode() else { return }
            try match.sendData(toAllPlayers: data, with: .reliable)
        } catch {
            print("Send data failed")
        }
    }

    class Coordinator: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate, GKLocalPlayerListener, GKGameCenterControllerDelegate {

        var parent: FinalMatchMaker

        init(_ parent: FinalMatchMaker) {
            self.parent = parent
            parent.dataModel = DataModel()
        }

        func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {

            viewController.dismiss(animated: true, completion: nil)

        }

        func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
            print("Personal Error: MatchMaker failed with error \(error.localizedDescription)")
        }

        func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
            viewController.dismiss(animated: true, completion: nil)
            parent.multiPlayerMatch = match
            match.delegate = self

            parent.savePlayers()

            if (
                parent.multiPlayerMatch?.expectedPlayerCount == 0)
            {
                print("Ready To Start our Match\n\n")
            }
        }

        // GKMatchDelegate methods

        func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {

            if parent.multiPlayerMatch != match {
                print("multiplayerMatch is nil ........")
                return
            }

            guard let model = DataModel.decode(data: data) else {return }

            parent.dataModel = model
         }

        func match(_ match: GKMatch, didFailWithError error: Error?) {

            if parent.multiPlayerMatch != match {
                return
            }
        }
    }
 }

3      

@The-Heymann: Hi, I am currently working on the same topic and basically the best way I found was to wrap the GKViewControllers in another UIViewController that cares for the display of the GKViewController. The decision is based on the fact that the GKTurnBasedMatchmakerViewController and the GKMatchmakerViewController can result in an optional during initilization. Where as for the authentication the GKAuthenticationViewController is only created conditionally any only if the player is not already authenticated.

At the moment authentication and match making is working for me in custom SwiftUI views. If you are interested on how I did achive it take a look at the current state here:

https://github.com/SwiftPackageRepository/GameKitUI.swift

And as always any help is welcome :) and greatly appreciated.

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.