Search code examples
iosswiftfacebookfacebook-ios-sdknsurl

App crashes after user logs in with Facebook


I got my app onto the App Store. Everything was working fine on my end, and apparently on the reviewers end.

After the app went live, some users reported crashing immediately after they log in with Facebook. Here's the code for where I think it's crashing (run right after users log in with Facebook):

import UIKit
import FBSDKCoreKit
import FBSDKLoginKit

protocol getUserDataDelegate {
    func gotData()
}

public var userEmailForMixpanel = ""
public var userNameForInvites = ""

class GetUserData: NSObject {

var facebookid:String = ""
var userEmail:String = ""
var userFirstName:String = ""
var userLastName: String = ""
var userGender:String = ""
var userBirthday:String = ""
var delegate = getUserDataDelegate?()

func returnUserData() {
    let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath:  "me", parameters: ["fields": "id, email, first_name, last_name, gender, birthday"])
    graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in

        if ((error) != nil)
        {
            print("Error: \(error)")
        }
        else
        {
            self.facebookid = (result.valueForKey("id") as? String)!
            self.userEmail = (result.valueForKey("email") as? String)!
            self.userFirstName = (result.valueForKey("first_name") as? String)!
            self.userLastName = (result.valueForKey("last_name") as? String)!
            self.userGender = (result.valueForKey("gender") as? String)!
            //self.userBirthday = (result.valueForKey("birthday") as? String)!

            userEmailForMixpanel = self.userEmail
            userNameForInvites = self.userFirstName

            NSUserDefaults.standardUserDefaults().setValue(userEmailForMixpanel, forKey: "userEmail")
            NSUserDefaults.standardUserDefaults().setValue(userNameForInvites, forKey: "userName")
            NSUserDefaults.standardUserDefaults().synchronize()

            Mixpanel.sharedInstanceWithToken("abdc")
            let mixpanel = Mixpanel.sharedInstance()
            mixpanel.registerSuperProperties(["Gender":self.userGender])

            print(self.facebookid)
            print(self.userEmail)
            print(self.userFirstName)
            print(self.userLastName)
            print(self.userGender)
            //print(self.userBirthday)

            self.checkIfUserExists()
        }
    })
}

func checkIfUserExists() {

    showTutorial = true

    let url:NSURL = NSURL(string: "url")!

    let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in

        let userTokenDataDictionary:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary

        if userTokenDataDictionary ["token"] != nil {
            userAccessToken = (userTokenDataDictionary["token"] as? String)!
            NSUserDefaults.standardUserDefaults().setValue(userAccessToken, forKey: "userAccessToken")
            NSUserDefaults.standardUserDefaults().synchronize()
            print("Token for Existing User:\(userAccessToken)")
            self.finishedGettingData()
        }

        if userTokenDataDictionary ["error"] != nil {
            userAccessToken = (userTokenDataDictionary["error"] as? String)!
            print(userAccessToken)
            print("User needs to be created")
            self.createNewUserFromFacebook()
        }
    }
    task.resume()
}

func createNewUserFromFacebook() {

    let url:NSURL = NSURL(string: "url")!

    print(url)

    let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in

        let userTokenDataDictionary:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary

        if userTokenDataDictionary ["token"] != nil {
            userAccessToken = (userTokenDataDictionary["token"] as? String)!
            NSUserDefaults.standardUserDefaults().setValue(userAccessToken, forKey: "userAccessToken")
            NSUserDefaults.standardUserDefaults().synchronize()
        }

        if userTokenDataDictionary ["error"] != nil {
            userAccessToken = (userTokenDataDictionary["error"] as? String)!
            print(userAccessToken)
        }

        print("Token for New User:\(userAccessToken)")
        self.finishedGettingData()
    }
    task.resume()
}

func checkIfUserHasUsedListenerApp() {

    let accessToken = NSUserDefaults.standardUserDefaults().stringForKey("userAccessToken")!

    let url:NSURL = NSURL(string: "url")!

    print(url)

    let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in

        let adDataDict:NSDictionary = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary

        if adDataDict ["used_ListenerApp"] != nil {
            let responseCode = adDataDict.valueForKey("used_ListenerApp") as! Bool
            print(responseCode)
            if responseCode == false {
                Mixpanel.sharedInstanceWithToken("abc")
                let mixpanel = Mixpanel.sharedInstance()
                mixpanel.track("New User Signed Up", properties: ["distinct_id":userEmailForMixpanel])
            }
            if responseCode == true {
                return
            }
        }
    }
    task.resume()
}

func finishedGettingData() {
    self.checkIfUserHasUsedListenerApp()

    Mixpanel.sharedInstanceWithToken("abc")
    let mixpanel = Mixpanel.sharedInstance()
    mixpanel.track("User Logged In", properties: ["distinct_id":userEmailForMixpanel])

    if let actualdelegate = self.delegate {
        actualdelegate.gotData()
    }
  }
}

It's only crashing for some users, not all. I even tried creating a loop that generates a bunch of user data to run it through this code, and I couldn't replicate the crash.

Any advice would be appreciated a lot.

UPDATE

It looks like it has to do with Facebook not returning an email address. I'll keep looking though.


Solution

  • I figured it out. Part of the problem was that Facebook wasn't returning an email address for some users, so I checked for that and if it didn't return an email, I created one with their Facebook ID to get them through the login process (fbid@facebook.mywebsite.com).

    Another part of the problem was that some users had logged into my website using an email address that was also assigned to their Facebook account, and tried logging in with Facebook on the app. I fixed this by having it merge their Facebook info with their existing account during the authorization process if an existing account is found.