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.
It looks like it has to do with Facebook not returning an email address. I'll keep looking though.
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.