I'm trying to get the user's profile picture form Facebook, to display it on his Account
screen. It works, but the problem is, it's too slow. The screen will load, and a good half a second later, the profile picture loads. Here is my viewDidLoad
code, where I make the graph API
request:
override func viewDidLoad() {
super.viewDidLoad()
currentUser = User.CurrentUser
editProfileButton.layer.cornerRadius = 2.5
// checking for logged in user
let defaults = NSUserDefaults.standardUserDefaults()
if FBSDKAccessToken.currentAccessToken() != nil {
// logged in through facebook, do nothing
updateCurrentUser()
} else {
// log in
presentLoginViewController()
}
userNameLabel.text = currentUser.first_name + " " + currentUser.last_name
userPhoneLabel.text = currentUser.phone_number
//getting profile picture: too slow for now.
if FBSDKAccessToken.currentAccessToken().hasGranted("user_photos") {
let userId = FBSDKProfile.currentProfile().userID
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"picture.type(large)"])
graphRequest.startWithCompletionHandler({(connection: FBSDKGraphRequestConnection!, response: AnyObject?, error: NSError!) in
if error != nil {
// error
}
if let resultDic = response as? NSDictionary {
let data = resultDic["picture"] as? NSDictionary
let dataDict = data!["data"] as? NSDictionary
let imageStringUrl = dataDict!["url"] as? String
let imageUrl = NSURL(string: imageStringUrl!)
let imageData = NSData(contentsOfURL: imageUrl!)
self.currentUser.profilePicture = UIImage(data: imageData!)
self.userPicImageView.image = self.currentUser.profilePicture
}
})
}
// user profile picture set up
userPicImageView.clipsToBounds = true
userPicImageView.contentMode = .ScaleAspectFill
userPicImageView.layer.cornerRadius = userPicImageView.frame.height / 2.67
}
Anyway I can make it faster?
For starters, putting the FBSDKGraphRequest
call further back in the life cycle is definitely not going to help you get your data faster. viewDidLoad
is a good place to put it - if you have to start it within a particular screen.
Next, you doing the image fetching asynchronously will help improve user experience. The code that you currently have will block the main thread, since the downloading process is on the main thread. I suggest you read up on NSURLSession
to deal with obtaining the images.
Techniques to get photos faster
There are a couple of reliable ways to get your photos "faster". One way is to grab a smaller image, if acceptable.
If you must have a large image, a good method is to abstract the network call in another class, and initialize the process as early as possible, for instance, in the didFinishLaunchingWithOptions
method of the AppDelegate.
For instance, you can have a class:
class FacebookDetails {
static let sharedInstance = FacebookDetails()
var image: UIImage?
private init() {
populateImage()
}
func populateImage() {
let graphRequest = FBSDKGraphRequest... //continue with populating image
}
}
Now you can initialize this class as early as possible in your application life cycle:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FacebookDetails.sharedInstance
return true
}
When you get to the view controller that requires the image, call FacebookDetails.sharedInstance.image
to retrieve the already loaded image (image load times is still subjected to network strength), but it's a method to start loading your images as early as possible in your application life cycle.