Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

facebook parse sign up swift

I've been struggling to create a facebook login/signup function in swift. i've been searching for a tutorial, but have not been able to find anything. So i've been trying to do it myself. It seem to work, but why is it not saving my facebookName, Gender and image in the database? It's saving it in the simulator but not when i'm using my ios 8 device?

i'm receiving this log message "User signed up and logged in through Facebook!", and a new user is added to the parse class, but not the name, image and gender...

@IBAction func login(sender: UIButton!) {




    var permissionArray = ["user_about_me", "user_relationships", "user_birthday", "user_location"]

    PFFacebookUtils.initializeFacebook()

    PFFacebookUtils.logInWithPermissions(permissionArray, block:  { (user: PFUser!, error: NSError!) in
        println(user)
        if user == nil {
            println(error.localizedDescription)


        } else {



            if user.isNew {



                var userQuery = PFUser.query()
                userQuery.getObjectInBackgroundWithId(PFUser.currentUser().objectId) {
                    (userObject: PFObject!, error: NSError!) -> Void in


                    var fbRequest = FBRequest.requestForMe()
                    fbRequest.startWithCompletionHandler { (connection: FBRequestConnection!, result:AnyObject!, error: NSError!) in


                        if error == nil {

                            //FACEBOOK DATA IN DICTIONARY
                            var userData = result as NSDictionary
                            var faceBookId = userData.objectForKey("id") as NSString
                            var faceBookName = userData.objectForKey("first_name") as NSString
                            var faceBookMiddle = userData.objectForKey("middle_name") as NSString
                            var faceBookGender = userData.objectForKey("gender") as NSString

                            var url:NSURL = NSURL.URLWithString(NSString(format:"https://graph.facebook.com/%@/picture?width=320", faceBookId))
                            var err: NSError?
                            var imageData :NSData = NSData.dataWithContentsOfURL(url, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)

                            var imageFile = PFFile(name: "image.jpg", data: imageData) as PFFile

                            println(userData)

                            userObject.setObject(faceBookName, forKey: "name")
                            userObject.setObject(imageFile, forKey: "file")
                            userObject.setObject(faceBookGender, forKey: "gender")

                            userObject.saveInBackground()



                            var sharedInstance:userSingleton = userSingleton.sharedInstance

                            sharedInstance.userName = (userObject.objectForKey("name") as NSString)
                            sharedInstance.userGender = (userObject.objectForKey("gender") as NSString)


                            (userObject.objectForKey("file") as PFFile).getDataInBackgroundWithBlock {
                                (theImageData: NSData!, error: NSError!) -> Void in

                                println(error)
                                if error == nil {

                                    sharedInstance.userImage = UIImage(data:theImageData)
                                }
                                self.performSegueWithIdentifier("LoginSegue", sender: self)
                            }


                        }
                    }
                }





                println("User signed up and logged in through Facebook!")
            } else {



                println("User logged in through Facebook!")
            }


        }

    })

}

}
like image 924
Peter Pik Avatar asked Sep 18 '14 16:09

Peter Pik


1 Answers

Assuming that you use Parse, here is how I do it. Personally I create a class Utils.swift where I put all the stuff that I want to reuse (or that I don't want to have in my ViewControllers):

class Utils {

    class func notLoggedIn() -> Bool {
        let user = PFUser.currentUser()
        // here I assume that a user must be linked to Facebook
        return user == nil || !PFFacebookUtils.isLinkedWithUser(user)
    }
    class func loggedIn() -> Bool {
        return !notLoggedIn()
    } 


    class func logInWithFacebook() {
        PFFacebookUtils.logInWithPermissions(["public_profile", "user_friends"]) {
            (user: PFUser!, error: NSError!) -> Void in
            if user == nil {
                NSLog("The user cancelled the Facebook login (user is nil)")
            } else {
                NSLog("The user successfully logged in with Facebook (user is NOT nil)")
                // HERE I SET A USER POINTER TO THE INSTALLATION
                // That way we can send push notifications to specific users
                if let installation = PFInstallation.currentInstallation() {
                    installation["user"] = PFUser.currentUser()
                    installation.saveEventually()
                }
                // THEN I GET THE USERNAME AND fbId
                Utils.obtainUserNameAndFbId()
            }
        }
    }


    class func obtainUserNameAndFbId() {
        if notLoggedIn() {
            return
        }
        let user = PFUser.currentUser() // Won't be nil because is logged in
        // RETURN IF WE ALREADY HAVE A USERNAME AND FBID
        // Note that we check the fbId because Parse automatically fills in the username with random numbers
        if let fbId = user["fbId"] as? String {
            if !fbId.isEmpty {
                println("we already have a username and fbId -> return")
                return
            }
        }
        // REQUEST TO FACEBOOK
        println("performing request to FB for username and IDF...")
        if let session = PFFacebookUtils.session() {
            if session.isOpen {
                println("session is open")
                FBRequestConnection.startForMeWithCompletionHandler({ (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
                    println("done me request")
                    if error != nil {
                        println("facebook me request - error is not nil :(")
                    } else {
                        println("facebook me request - error is nil :)")
                        println(result)
                        // You have 2 ways to access the result:
                        // 1)
                        println(result["name"])
                        println(result["id"])
                        // 2)
                        println(result.name)
                        println(result.objectID)
                        // Save to Parse:
                        PFUser.currentUser().username = result.name
                        PFUser.currentUser().setValue(result.objectID, forKey: "fbId")
                        PFUser.currentUser().saveEventually() // Always use saveEventually if you want to be sure that the save will succeed
                    }
                })
            }
        }
    }

}

Then you can simply call Utils.logInWithFacebook() when you want to perform the login.

Note that, because the facebook me request can fail, it's not guaranteed that you will successfully save the username and facebook ID to Parse. That's why I create the method Utils.obtainUserNameAndFbId(), which I call in application(_: didFinishLaunchingWithOptions) (it can be called every launch because it will only perform the request to FB until it succeeds).

like image 187
Albert Vila Calvo Avatar answered Sep 23 '22 06:09

Albert Vila Calvo