New Xcode UIViewControllerRepresentables must be value types for emulator but not real device

Viewed 31

I'm running into an issue after xcode updated in some way (guess it was a new xcode version). When I try to run the app in the new emulators I'm getting the error Thread 1: Fatal error: UIViewControllerRepresentables must be value types: SignInWithAppleToFirebase but everything still runs as expected when I run on my physical device. When I look around for the error I find some explanations that sorta make sense and apply to the SignInWithAppleToFirebase class. The SignInWithAppleToFirebase is below but I sorta want an explination of why things are working on my physical device before I go reworking this class into a struct (was presenting me with some issues I'd rather not deal with if this is just some bug with xcode).

   final class SignInWithAppleToFirebase: UIViewControllerRepresentable {
    private var appleSignInDelegates: SignInWithAppleDelegates! = nil
    private let onLoginEvent: ((SignInWithAppleToFirebaseResponse) -> ())?
    private var currentNonce: String?
    
    init(_ onLoginEvent: ((SignInWithAppleToFirebaseResponse) -> ())? = nil) {
        self.onLoginEvent = onLoginEvent
    }
    
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIHostingController(rootView: SignInWithAppleButton().onTapGesture(perform: showAppleLogin))
        return vc as UIViewController
    }
  
    func updateUIViewController(_ uiView: UIViewController, context: Context) {
        
    }
    
    private func showAppleLogin() {
        let nonce = randomNonceString()
        currentNonce = nonce
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = sha256(nonce)
        
        performSignIn(using: [request])
    }

    private func performSignIn(using requests: [ASAuthorizationRequest]) {
        guard let currentNonce = self.currentNonce else {
            return
        }
        appleSignInDelegates = SignInWithAppleDelegates(window: nil, currentNonce: currentNonce, onLoginEvent: self.onLoginEvent)

        let authorizationController = ASAuthorizationController(authorizationRequests: requests)
        authorizationController.delegate = appleSignInDelegates
        authorizationController.presentationContextProvider = appleSignInDelegates
        authorizationController.performRequests()
    }



    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    private func randomNonceString(length: Int = 32) -> String {
        precondition(length > 0)
        let charset: Array<Character> =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
        var result = ""
        var remainingLength = length

        while remainingLength > 0 {
            let randoms: [UInt8] = (0 ..< 16).map { _ in
                var random: UInt8 = 0
                let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
                if errorCode != errSecSuccess {
                    fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
                }
                return random
            }

            randoms.forEach { random in
                if length == 0 {
                    return
                }

                if random < charset.count {
                    result.append(charset[Int(random)])
                    remainingLength -= 1
                }
            }
        }

        return result
    }

    private func sha256(_ input: String) -> String {
        let inputData = Data(input.utf8)
        let hashedData = SHA256.hash(data: inputData)
        let hashString = hashedData.compactMap {
        return String(format: "%02x", $0)
        }.joined()

        return hashString
    }
}
0 Answers
Related