20

I've just "upgraded" my Facebook SDK to 4.0 for my iOS app.

I've got the log in working okay, however, according to the documentation, I'm now supposed to use FBSDKProfile.currentProfile() to access profile information.

However, this value always seems to be nil, even though my profile picture is being displayed (through a FBSDKProfilePictureView) and my FBSDKAccessToken.currentAccessToken() is not nil.

This is my login ViewController:

import UIKit

class LoginViewController: UIViewController, FBSDKLoginButtonDelegate {

    @IBOutlet weak var fbLoginButton: FBSDKLoginButton!
    @IBOutlet weak var fbProfilePicture: FBSDKProfilePictureView! //displays a picture

    override func viewDidLoad() {
        super.viewDidLoad()
        self.fbLoginButton.delegate = self
        FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
        if FBSDKAccessToken.currentAccessToken() != nil {
            println("\(FBSDKAccessToken.currentAccessToken().userID)") //works
        }
        self.fbLoginButton.readPermissions = ["public_profile", "email", "user_friends"]
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
        println(FBSDKProfile.currentProfile()) //is nil
    }

    func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
    }
}

Any ideas?

fanfan
  • 504
  • 1
  • 4
  • 13

8 Answers8

27

Don't forget FBSDKProfile.enableUpdatesOnAccessTokenChange(true)!! I struggled with this for awhile until I found that in the docs. Then subscribing to notifications on FBSDKProfileDidChangeNotification should work for the FBSDKLoginButton.

Full Example... I hook up loginButton via Interface Builder

class LoginController: UIViewController, FBSDKLoginButtonDelegate {

@IBOutlet var loginButton: FBSDKLoginButton!

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.delegate = self;
    FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "onProfileUpdated:", name:FBSDKProfileDidChangeNotification, object: nil)

}

func onProfileUpdated(notification: NSNotification)
{
}

func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!){

}

func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {

}

}

Johnny Z
  • 14,329
  • 4
  • 28
  • 35
  • This did not help me. I had to manually make request to "me" to get user profile. – nerowolfe Mar 29 '15 at 06:49
  • Correction: it works now. So, the main anchors: make FBSDKProfile.enableUpdatesOnAccessTokenChange(true) in viewDidLoad. And also you should subscribe to name:FBSDKProfileDidChangeNotification because you will know about changed profile only after this notification. But the problem is that this profile does not contain email of user. To get email you should use "me" request – nerowolfe Mar 29 '15 at 06:55
  • Also, might note, I could not get profile without using FBSDKLoginButton. So, with just FBSDKLoginManager this method does not work – nerowolfe Mar 29 '15 at 07:00
  • for obj-c: **[FBSDKProfile enableUpdatesOnAccessTokenChange:YES];** and this was a big help... thanks! – Derek Apr 10 '15 at 18:10
  • Thank you for the complete example – Damo May 28 '15 at 13:20
  • This is the key line, thanks. BTW, by the sample code `Scrumptious`, this line can be put in the function `didFinishLaunchingWithOptions` AppDelegate – Dino Tw May 15 '16 at 21:13
  • Eric Alford's suggestion works easily without having to listen to notifications and all other extra steps – ArdenDev Jul 30 '16 at 17:37
  • Thank you. I don't think that interface was available when I wrote this answer. All those reading, please see Eric Alford's answer – Johnny Z Jul 31 '16 at 19:28
  • For Swift 3.0 NotificationCenter.default.addObserver(self, selector: #selector(ViewController.handleFBDelegate), name:NSNotification.Name.FBSDKProfileDidChange, object: nil) – JoakimE Nov 13 '16 at 22:11
13

For those of you who are looking for a more updated answer and a cleaner approach than using the NSNotificationCenter, there is a class method on FBSDKProfile that you can call after logging in that looks like:

[FBSDKProfile loadCurrentProfileWithCompletion:^(FBSDKProfile *profile, NSError *error) {

}];
Eric Alford
  • 926
  • 7
  • 11
11

The FBSDKProfile fetch may not have been completed by the time of the login callback. Instead you can observe for a 'FBSDKProfileDidChangeNotification' notification post.

Chris Pan
  • 1,903
  • 14
  • 16
  • Seems this is the case, thanks. How (and when) exactly should I observe for a change to that string? – fanfan Mar 27 '15 at 22:54
  • Like other NSNotification notification posts, you can typically observe it in the viewDidLoad of any view controllers that need to do work with that data. – Chris Pan Mar 30 '15 at 02:54
7

I'm in objc but ran into this problem as well.

First, Johnny Z's answer is correct that you have to explicitly enable the FBSDKProfile class by setting 'enableUpdatesOnAccessTokenChange' to true and then observing changes. In fact, that's what FBSDKProfile is doing internally according to the header comments.

However, as noted by fanfan in a comment, the FBSDKProfile doesn't have all of the fields you might be interested in. I ended up not using FBSDKProfile and just made a graph request for 'me' like so:

    [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:nil]
         startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             if (error) {
                 CLS_LOG(@"Login error: %@", [error localizedDescription]);
                 return;
             }

             NSLog(@"fecthed user: %@", result);
}];

Note: You can still observe changes with the 'FBSDKProfileDidChangeNotification' notification. Read FBSDKAccessToken.h comments for documentation of this notification and the keys it will send.

Chad Pavliska
  • 1,233
  • 12
  • 17
6

In objective-C I used the following approach based on comments in this thread.

If this flag is set to yes, after login or logout a notification will be called. So in viewDidLoad add this line of code and add the notification to be called after user profile get received.

[FBSDKProfile enableUpdatesOnAccessTokenChange:YES];

[[NSNotificationCenter defaultCenter] addObserverForName:FBSDKProfileDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
     //do whatever you want
}];

All information in this link https://developers.facebook.com/docs/facebook-login/ios/v2.3#profiles

Pedro Romão
  • 2,285
  • 28
  • 22
3

It seems like you need to call the AppDelegate method to initialize the SDK before you call enableUpdatesOnAccessTokenChange:YES

I made my AppDelegate didFinishLaunching method like this

BOOL fbsdk = [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; [FBSDKProfile enableUpdatesOnAccessTokenChange:YES]; return fbsdk;

That seemed to work. You still might need to do a /me request if you need items not in the profile object.

Brian Broom
  • 497
  • 4
  • 11
2

I had similar problem with [FBSDKProfile currentProfile],but in Objective-C, you can also get user profile's properties from Graph API with response to https://graph.facebook.com/me?access_token= with your currentAccessToken.

Aadil Keshwani
  • 1,385
  • 1
  • 18
  • 29
  • 1
    It seems this may be the "proper" way anyway, as the FBSDKProfile is missing some information (such as email). – fanfan Mar 30 '15 at 23:33
0

Swift 4 version,

FBSDKProfile.loadCurrentProfile(completion: {
        profile, error in
        let url = profile?.imageURL(for: FBSDKProfilePictureMode.square, size:  self.imageview.frame.size)
    })
cnu
  • 443
  • 4
  • 9