web-dev-qa-db-ja.com

Swift --uiDelegateはUIViewControllerであるか、signIn:presentViewController:&signIn:dismissViewController:メソッドを実装する必要があります

Crashlyticsから、Googleログインプロセスで大量のクラッシュレポートを受け取っています。クラッシュレポートは次のとおりです。

_Fatal Exception: NSInvalidArgumentException
uiDelegate must either be a |UIViewController| or implement the |signIn:presentViewController:| and |signIn:dismissViewController:| methods from |GIDSignInUIDelegate|.

Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x1837f2db0 __exceptionPreprocess
1  libobjc.A.dylib                0x182e57f80 objc_exception_throw
2  CoreFoundation                 0x1837f2cf8 -[NSException initWithCoder:]
3  Hello English                  0x100583d18 -[GIDSignIn assertValidUIDelegate] (GIDSignIn.m:512)
4  Hello English                  0x1005861dc -[GIDSignIn signInWithOptions:] (GIDSignIn.m:961)
5  Hello English                  0x10058a0e4 -[GIDSignInButton pressed] (GIDSignInButton.m:385)
6  UIKit                          0x188988be8 -[UIApplication sendAction:to:from:forEvent:]
7  UIKit                          0x188988b64 -[UIControl sendAction:to:forEvent:]
8  UIKit                          0x188970870 -[UIControl _sendActionsForEvents:withEvent:]
9  UIKit                          0x188988454 -[UIControl touchesEnded:withEvent:]
10 UIKit                          0x188988084 -[UIWindow _sendTouchesForEvent:]
11 UIKit                          0x188980c20 -[UIWindow sendEvent:]
12 UIKit                          0x18895104c -[UIApplication sendEvent:]
13 UIKit                          0x18894f628 _UIApplicationHandleEventQueue
14 CoreFoundation                 0x1837a909c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
15 CoreFoundation                 0x1837a8b30 __CFRunLoopDoSources0
16 CoreFoundation                 0x1837a6830 __CFRunLoopRun
17 CoreFoundation                 0x1836d0c50 CFRunLoopRunSpecific
18 GraphicsServices               0x184fb8088 GSEventRunModal
19 UIKit                          0x1889ba088 UIApplicationMain
20 Hello English                  0x10029b2cc main (AppDelegate.Swift:26)
21 libdispatch.dylib              0x18326e8b8 (Missing)
_

これまでに試しました:

  1. GIDSignIn.sharedInstance().uiDelegate = selfviewDidLoad()からviewDidAppear(animated: Bool)に移動しました
  2. また、GIDSignInUIDelegateの3つのメソッドすべてを実装しましたが、成功しませんでした。
  3. 私たちのビューコントローラーはUIViewControllerの直接の子ではありませんでしたが、現在はそうであり、クラッシュはまだカウントされています。
  4. 単純なUIButtonを使用していたので、それがクラッシュの原因である可能性があると考えました(非論理的ですが、試しました)。 GIDSignInButtonに変更しましたが、クラッシュ数は減少しませんでした。

今のところ、_Google Login_プロセスを削除しましたが、それは解決策ではありません。そして奇妙なことに、このクラッシュを最後に再現することはできません。これらのクラッシュはCrashlyticsでのみ発生します。

だから誰かが解決策を持っていますか?

10
Ravi Sisodia

最後に多くの努力をした後、解決策を見つけました。私の環境は

スウィフト3、

iOS 10.3.x、

Xcode 8.3.2

ここに完全なソリューションを投稿する

import UIKit
import GoogleSignIn

class ViewController: UIViewController, GIDSignInUIDelegate, GIDSignInDelegate {

    @IBOutlet weak var signInButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // set delegates
        GIDSignIn.sharedInstance().delegate = self
        GIDSignIn.sharedInstance().uiDelegate = self

        let buttonFrame : CGRect = CGRect.init(x: 0, y: 0, width: 100, height: 50)
        let gdSignInButton = GIDSignInButton.init(frame:buttonFrame)
        gdSignInButton.center = view.center
        view.addSubview(gdSignInButton)

        //  gdSignInButton.addTarget(self, action: #selector(self.didTapSignOut(sender: self.gdSignInButton)), for: UIControlEvents.touchUpInside)
    }

    @IBAction func didTapSignOut(sender: GIDSignInButton) {
        GIDSignIn.sharedInstance().signOut()
    }

    func sign(inWillDispatch signIn: GIDSignIn!, error: Error!) {

        guard error == nil else {

            print("Error while trying to redirect : \(error)")
            return
        }

        print("Successful Redirection")
    }


    //MARK: GIDSignIn Delegate

    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!)
    {
        if (error == nil) {
            // Perform any operations on signed in user here.
            let userId = user.userID                  // For client-side use only!
            print("User id is \(userId)")

            let idToken = user.authentication.idToken // Safe to send to the server
            print("Authentication idToken is \(idToken)")
            let fullName = user.profile.name
            print("User full name is \(fullName)")
            let givenName = user.profile.givenName
            print("User given profile name is \(givenName)")
            let familyName = user.profile.familyName
            print("User family name is \(familyName)")
            let email = user.profile.email
            print("User email address is \(email)")
            // ...
        } else {
            print("ERROR ::\(error.localizedDescription)")
        }
    }

    // Finished disconnecting |user| from the app successfully if |error| is |nil|.
    public func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!)
    {

    }



}

私のAppDelegateは次のようになります。

import UIKit
import Google
import GoogleSignIn

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // Initialize sign-in
        var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")



        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        return GIDSignIn.sharedInstance().handle(url as URL!,
                                                 sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
    }


}
12
Satish

これらの行は、viewWillAppearUIViewControllerメソッドで記述する必要があります。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)

    GIDSignIn.sharedInstance().uiDelegate = self
    GIDSignIn.sharedInstance().delegate = self
}
7
Rehan

delegate of theGoogleとfirebaseを適切に実装する必要があります
このように追加

class ViewController: UIViewController, GIDSignInDelegate,GIDSignInUIDelegate    

viewDidLoadにこれらの行を追加します

GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().signIn()
5
Sultan Ali

以下を含めるだけです

func sign(_ signIn: GIDSignIn!, dismiss viewController: UIViewController!) {
    print("dismissing Google SignIn")
}

func sign(_ signIn: GIDSignIn!, present viewController: UIViewController!) {
    print("presenting Google SignIn")
}
2
Alexandros

この行をviewDidAppearに追加する必要があります。

override    func    viewDidAppear(_ animated: Bool) {
        GIDSignIn.sharedInstance().delegate    =    self
        GIDSignIn.sharedInstance().uiDelegate    =    self
    }
0
Nitesh Kumar

このエラーは、カスタムビューコントローラークラスをストーリーボードでUIViewControllerTookに設定するのを忘れた場合にも表示されます。

これを行うには->ストーリーボードに移動します-> ViewControllerを選択します-> Identity Explorerに移動し、空白の場合はクラスを設定します

以下の画像を参照してください

画像を表示

0
Prashant Sawant

私の解決策(iOS 10.0)は、viewDidAppear:メソッドでビューコントローラーをUIデリゲートとして割り当てることでした...

-(void)viewDidAppear{
    [super viewDidAppear];
    [GIDSignIn sharedInstance].uiDelegate = self;
}
0
Tjalsma

これは単に、次のデリゲートメソッドを実装する必要があることを意味します。

_GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
_

これはviewDidLoad()で設定できます。


特別なケース

複数のViewController(登録画面やログイン画面など)でGoogleサインインを使用している場合は、画面が変更されたときに代理人を更新する必要があります。競合を避けるために、viewDidAppear()に設定することをお勧めします。これにより、画面を前後に切り替える場合に、デリゲート参照が現在のViewControllerで更新されます。

0
Chintan Shah

私もこのエラーに遭遇し、2つのケースでそれを観察しました:

  1. GoogleSignInボタンの@IBActionを作成し、次の両方の行を含めました。

    @IBAction func googleSignInButton(_ sender:Any){GIDSignIn.sharedInstance()。signIn()GIDSignIn.sharedInstance()。uiDelegate = self}

ただし、uiDelegateの割り当ては、@ IBActionではなく、viewDidLoadにある必要があります。

GIDSignIn.sharedInstance().uiDelegate = self
  1. 私の他の場合、uiDelegateはUIViewControllerであるため、追加のメソッドを指定する必要はありませんでした。そして、ここにある他のポスターのように、私はすべての指示に従ったと確信していましたが、Googleサインインボタンをクリックするたびにこのエラーが表示されていました。

根本的な原因は、新しいUIViewControllerクラス「DoLoginVC.Swift」を作成したことですが、このカスタムクラスをストーリーボードのUIViewControllerにマップしませんでした。見落とし。カスタムクラスマッピングを追加した後、すべてが機能し始めました。

このエラーが表示された場合は、ストーリーボードに移動してViewControllerに移動し、添付のスクリーンショットのようにカスタムクラスを指定したことを確認してください。

enter image description here

0
Lucy

GoogleSignIn SDK 5.以降ではGIDSignInUIDelegateが取り消されました

だから代わりに

GIDSignIn.sharedInstance().uiDelegate = self

ログインビューの表示に準拠するために、以下の行を追加します

GIDSignIn.sharedInstance()?.presentingViewController = self