Terminating app due to uncaught exception 'NSInvalidArgumentException' - ios google sign in

孤街醉人 提交于 2019-12-24 15:14:04

问题


I'm implementing the google sign in process taken from this tutorial https://developers.google.com/identity/sign-in/ios/sign-in?configured=true&ver=swift

as I can see there the author wrote:

In these examples, the view controller is a subclass of UIViewController. If, in your project, the class that implements GIDSignInUIDelegate is not a subclass of UIViewController, implement the signInWillDispatch:error:, signIn:presentViewController:, and signIn:dismissViewController: methods of the GIDSignInUIDelegate protocol.

so following his advices I wrote as follows:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {



func application(application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Initialize sign-in
        var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")

        GIDSignIn.sharedInstance().delegate = self

        return true
}

// [START openurl]
func application(application: UIApplication,
    openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
        return GIDSignIn.sharedInstance().handleURL(url,
            sourceApplication: sourceApplication,
            annotation: annotation)
}
// [END openurl]

@available(iOS 9.0, *)
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
    return GIDSignIn.sharedInstance().handleURL(url,
        sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as! String?,
        annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
}

// [START signin_handler]
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
    withError error: NSError!) {
        if (error == nil) {
            print("Signed in!")
        } else {
            print("\(error.localizedDescription)")
        }
}
// [END signin_handler]

// [START disconnect_handler]
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user:GIDGoogleUser!,
    withError error: NSError!) {
        // Perform any operations when the user disconnects from app here.
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName(
            "ToggleAuthUINotification",
            object: nil,
            userInfo: ["statusText": "User has disconnected."])
        // [END_EXCLUDE]
}

I also have a class called LoginScreen.swift that contains:

import UIKit

class LoginScreen: UIViewController, GIDSignInUIDelegate {

     override func viewDidLoad() {
    super.viewDidLoad()
    GIDSignIn.sharedInstance().uiDelegate = self

    // Uncomment to automatically sign in the user.
    GIDSignIn.sharedInstance().signInSilently()

}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    GIDSignIn.sharedInstance().uiDelegate = self

     GIDSignIn.sharedInstance().signInSilently()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func signInWillDispatch(signIn: GIDSignIn!, error: NSError!) {
    print("Nothing!")
}

// Present a view that prompts the user to sign in with Google
func signIn(signIn: GIDSignIn!,
    presentViewController viewController: UIViewController!) {
        self.presentViewController(viewController, animated: true, completion: nil)
}

// Dismiss the "Sign in with Google" view
func signIn(signIn: GIDSignIn!,
    dismissViewController viewController: UIViewController!) {
        self.dismissViewControllerAnimated(true, completion: nil)
}


}

and when I run the app I see the button sign in with google. But when I click it, I see the error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'When |allowsSignInWithWebView| is enabled, uiDelegate must
either be a |UIViewController| or implement the
|signIn:presentViewController:| and |signIn:dismissViewController:| 
methods from |GIDSignInUIDelegate|.'

What is the problem here? I thought I included the necessary methods...

============ EDIT - as a follow up to @emrys57 questions:

I have the GoogleService-Info.plist file attached in my project:

When I comment out the 3 methods (presentViewController, dismissViewController and signInWillDispatch) nothing changes - I'm still getting the same error..

About the screens - this is how my storyboard looks like:

and I want to display the google log in button on the 3rd screen.

The second screen here contains a Tutorial and its code is so far as follows:

import UIKit

class Tutorial: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let background = CAGradientLayer().greenBlue()
        background.frame = self.view.bounds
        self.view.layer.insertSublayer(background, atIndex: 0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

And one more thing - when I turn on the app I see now the google login button:

And when I click it - I'm getting the mentioned error:

2016-02-13 09:47:49.578 myapp[20870:800499] *** Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason: 'When
|allowsSignInWithWebView| is enabled, uiDelegate must either be a
|UIViewController| or implement the |signIn:presentViewController:| and
|signIn:dismissViewController:| methods from |GIDSignInUIDelegate|.'

*** First throw call stack:
(...)

so I guess the LoginScreen is running when I hit the button...

=========== another EDIT:

When I copied the code from my LoginScreen to the class ViewController and added button there - everything worked fine, I see a google sign in button and I can log in! BUT - the button appears on the first screen of the app and that's not what I want. I want it to appear on the 3rd screen (after the tutorial). Does anybody know what is going on here and why I can't put the login button on the 3rd screen?


回答1:


I know it's too late but will help for others if you put the GIDSignIn.sharedInstance().uiDelegate = self into viewDidAppear instead viewDidLoad, that's worked for me!




回答2:


func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!) is a method from the GIDSignInUIDelegate protocol but the code above states that AppDelegate adopts the GIDSignInDelegate (not "UI") protocol, and your GIDSignInUIDelegate does not provide the methods. Either the classes are adopting the wrong protocols or the methods are in the wrong classes.




回答3:


Not the problem for this question, but this may also happen due to a automatic Obj-C to Swift 3 naming generation, causing method signatures of GIDSignInUIProtocol to be different than what's expected by Google's SDK.

Adding these forward methods to the GIDSignInUIProtocol implementation will solve the issue for this case -

func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!) {
    self.sign(signIn, present: viewController)
}

func signIn(signIn: GIDSignIn!, dismissViewController viewController: UIViewController!) {
    self.sign(signIn, dismiss: viewController)
}



回答4:


Updated for Swift 3:

used below lines of code in signIn Button Action Method:

GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().signIn()

Note: Comments above lines of code if you are using it anywhere in your ViewController...! otherwise it will be fine.

Enjoy Learning....!




回答5:


In case its helpful I posted the root cause of this error in my case over here in this other post.



来源:https://stackoverflow.com/questions/35371393/terminating-app-due-to-uncaught-exception-nsinvalidargumentexception-ios-goo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!