swiftxcodeauthenticationfacebook-sdk-4.x

How to fix crash in Facebook LogIn button by pressing cancel


For educational purposes I'm trying to create a simple app to login with Facebook.

I imported the SD manually without using Cocoa Pods.

This is the code in my app delegates:

import UIKit
import FBSDKCoreKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
        return true
    }

    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        return FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        FBSDKAppEvents.activateApp()
    }
}

In the ViewController instead, I declared the labels and an immageView where I'm going to enter the data downloaded from facebook. At this point I show you the code written in the ViewController:

import UIKit
import FBSDKCoreKit
import FBSDKLoginKit

class ViewController: UIViewController, FBSDKLoginButtonDelegate {
    @IBOutlet weak var lbl_fbid: UILabel!
    @IBOutlet weak var lbl_fbdirstname: UILabel!
    @IBOutlet weak var lbl_fblastname: UILabel!
    @IBOutlet weak var lbl_fbemail: UILabel!
    @IBOutlet weak var img_fbprofilepic: UIImageView!

    func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {

        if (error == nil) {
            print("Connected")
                        let r = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"email,first_name,last_name,picture.type(large)"], tokenString: FBSDKAccessToken.current()?.tokenString, version: nil, httpMethod: "GET")
                        r?.start(completionHandler: { (test, result, error) in
                        if let id : NSString = (result! as AnyObject).value(forKey: "id") as? NSString {
                            print("id: \(id)")
                            self.lbl_fbid.text = "ID: \(id)"
                        }
                            if let imageURL = (((((result! as AnyObject).value(forKey: "picture")) as AnyObject).value(forKey: "data")) as AnyObject).value(forKey: "url") as? NSString{
                            print("img url: \(imageURL)")
                            let url = URL(string: imageURL as String)
                            DispatchQueue.global().async {
                                let data = try? Data(contentsOf: url!)
                                DispatchQueue.main.async {
                                    self.img_fbprofilepic.image = UIImage(data: data!)
                                }
                            }
                        }
                        if let first_name : NSString = (result! as AnyObject).value(forKey: "first_name") as? NSString {
                            print("first_name: \(first_name)")
                            self.lbl_fbdirstname.text = "First_Name: \(first_name)"
                        }
                        if let last_name : NSString = (result! as AnyObject).value(forKey: "last_name") as? NSString {
                            print("last_name: \(last_name)")
                            self.lbl_fblastname.text = "First_Name: \(last_name)"
                        }
                        if let email : NSString = (result! as AnyObject).value(forKey: "email") as? NSString {
                            print("email: \(email)")
                            self.lbl_fbemail.text = "Email: \(email)"
                        }

                            if(error == nil)
                            {
                                print(result as Any)
                            }

                        })

        } else  {
            print(error.localizedDescription)
        }
    }

    func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
        print("Disconnected")

            self.lbl_fbid.text = "ID: "
            self.lbl_fbdirstname.text = "First_Name: "
            self.lbl_fblastname.text = "First_Name: "
            self.lbl_fbemail.text = "Email: "
            self.img_fbprofilepic.image = nil
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let loginButton = FBSDKLoginButton()
        loginButton.readPermissions = ["public_profile", "email"]
        loginButton.center = self.view.center
        loginButton.delegate = self
        self.view.addSubview(loginButton)
    }
}

Everything works here. I can log in via facebook and I can populate the labels and the image with the downloaded data.

So the problem is another. If by chance, during the login, I click on the cancel button the app crashes and the console gives me this:

Connected
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

and I get redirected to this line in the AppDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate {

with this message in red "Thread 1: signal SIGABRT".


Solution

  • I solved by structuring the function loginButton in this way:

    func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
            if (error == nil) {
                if(result.isCancelled){
                    print("login cancelled")
                }else{
                    //code here
                    print("Connected")
                }
            } else  {
                print(error.localizedDescription)
            }
        }
    

    bye ;)