Facebook SDK - Profile picture is throwing an unwrapping error - ios

I use Parse with Facebook login so if I try to get the profile picture of the logged in user I get the error:
unexpectedly found nil while unwrapping an Optional value
I think the version of the SDK must be v4.5.1, and I use the Xcode 7 beta with Swift 2.
I use the code below to get the job done, but it won't run.
let pictureRequest = FBSDKGraphRequest(graphPath: "me/picture?type=large&redirect=false", parameters: ["fields": "url"])
pictureRequest.startWithCompletionHandler({ (connection, result, error: NSError!) -> Void in
if error == nil {
print("\(result)")
if let dictPic = result as? Dictionary<String, AnyObject> {
print(dictPic)
let url: String = dictPic["data{url}"] as AnyObject? as! String // <- this line is causing the error
print(url)
let URLRequest = NSURL(string: url)
let URLRequestNeeded = NSURLRequest(URL: URLRequest!) NSURLSession.sharedSession().dataTaskWithRequest(URLRequestNeeded, completionHandler: { (data, response, error) -> Void in
let picture = self.scaleImageWith(UIImage(data: data!)!, and: CGSizeMake(75, 75))
let pictureData = UIImagePNGRepresentation(picture)
let endPicture = PFFile(data: pictureData!)
PFUser.currentUser()!.setObject(endPicture, forKey: "picture")
PFUser.currentUser()!.saveInBackground()
})
}
} else {
print("\(error)")
}

Related

iOS - Swift Facebook Graph Request completion handler - Type of expression is ambiguous without more context

I'm trying to make this Facebook Graph request work but I get two errors :
Cannot conver value of type '(,,_) throws -> Void' to expected argument type 'FBSDKGraphRequestHandler!' - On line #6
Type of expression is ambiguous without more context - On line #14
This is my code for viewDidLoad() :
override func viewDidLoad() {
super.viewDidLoad()
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, gender"])
graphRequest.startWithCompletionHandler( {
(connection, results, error) -> Void in
if error != nil {
print(error)
} else if let result = results {
PFUser.currentUser()?["gender"] = result["gender"]
PFUser.currentUser()?["name"] = result["name"]
try PFUser.currentUser()?.save()
let userId = result["id"] as! String
let facebookProfilePictureUrl = "https://graph.facebook.com/" + userId + "/picture?type=large"
if let fbpicUrl = NSURL(string: facebookProfilePictureUrl) {
if let data = NSData(contentsOfURL: fbpicUrl) {
self.profilePicture.image = UIImage(data: data)
let imageFile:PFFile = PFFile(data: data)!
PFUser.currentUser()?["image"] = imageFile
try PFUser.currentUser()?.save()
}}}
})
}
If you have any suggestion for how to fix that, it would really appreciated if you could let me know! Thanks.
Problem is you are using try without do-catch.
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, gender"])
graphRequest.startWithCompletionHandler { (connection, results, error) -> Void in
if error != nil {
print(error)
} else if let result = results {
PFUser.currentUser()?["gender"] = result["gender"]
PFUser.currentUser()?["name"] = result["name"]
do {
try PFUser.currentUser()?.save()
} catch let ex {
print(ex)
}
let userId = result["id"] as! String
let facebookProfilePictureUrl = "https://graph.facebook.com/" + userId + "/picture?type=large"
if let fbpicUrl = NSURL(string: facebookProfilePictureUrl),
data = NSData(contentsOfURL: fbpicUrl) {
self.profilePicture.image = UIImage(data: data)
let imageFile:PFFile = PFFile(data: data)!
PFUser.currentUser()?["image"] = imageFile
do {
try PFUser.currentUser()?.save()
} catch let ex {
print(ex)
}
}
}
}
or you can use try? or try!
try? PFUser.currentUser()?.save()
But using save() method is not good choose. It lock current thread. Better if you will use saveInBackground with completion block if you need to be sure it saved successfully or saveEventually.
Btw. your code is not very well formatted and really hard to read...

Cannot convert value of type FBSDKGraphRequestHandler

I'm getting the following error when I try to make a data request using the Facebook SDK:
Cannot convert value of type '(_,_,_) throws -> Void' to expected argument type 'FBSDKGraphRequestHandler!'
Here is the relevant code where the error is occurring. I found this in a tutorial but I think it worked with older versions of XCode. I'm using the latest version 7.2.1.
UPDATED
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, gender, email"])
graphRequest.startWithCompletionHandler ({ [weak self] connection, result, error in
if error != nil {
//onError()
print(error)
return
} else {
//get results
PFUser.currentUser()?["gender"] = result["gender"]
PFUser.currentUser()?["name"] = result["name"]
try PFUser.currentUser()?.save()
let userId = result["id"] as! String
let facebookProfilePictureUrl = "https://graph.facebook.com/" + userId + "/picture?type=large"
if let fbpicUrl = NSURL(string: facebookProfilePictureUrl) {
if let data = NSData(contentsOfURL: fbpicUrl) {
self.profilePic.image = UIImage(data: data)
let imageFile:PFFile = PFFile(data: data)!
PFUser.currentUser()?["image"] = imageFile
try PFUser.currentUser()?.save()
}
}
}
})
Thanks!
PICTURE (click on the image to make it larger)
http://imgur.com/skCa1VB
I hope you are using the latest FBSDK in that the completionHandler: has been changed. See the below code:
let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: param)
graphRequest.startWithCompletionHandler { [weak self] connection, result, error in
if error != nil {
//onError()
print(error.description)
return
}else{
let fbResult = result as! Dictionary<String, AnyObject>
//Do You rest of the code here
}
})

Can't return output of closure using graph api

If I call this method to obtain a Facebook profile picture it does not work, response gets printed with the data but when I return it its nil, can anyone help?
func getProfilePicture() -> NSData?{
var response:NSData?
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"picture.type(large)"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if error != nil {
print("login error: \(error!.localizedDescription)")
return
}
let json = JSON(result)
let profilePicture = json["picture"]["data"]["url"].stringValue
if let url = NSURL(string: profilePicture) {
if let pictureData = NSData(contentsOfURL: url){
response = pictureData
}
}
})
print(response)
return response
}
The Facebook call is using an async completionblock and your return statement will return nil before the call is done loading. That is why you also should use a completion block in your method.
Here is an example how to do this:
func getProfilePicture(completion: (pictureData: NSData?, error: NSError?) -> Void) {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"picture.type(large)"])
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
var pictureData: NSData?
let json = JSON(result)
let profilePicture = json["picture"]["data"]["url"].stringValue
if let url = NSURL(string: profilePicture) {
pictureData = NSData(contentsOfURL: url)
}
completion(pictureData: pictureData, error: error)
})
}
You can call this code like this:
self.getProfilePicture {(pictureData, error) -> Void in
if error != nil {
print("login error: \(error!.localizedDescription)")
}
print(pictureData)
}

Can't get value from Google-Books JSON API

I'm using a bar code scanner to get data on a scanned book using the google books api. I successfully call the API and get a JSON object back.
I'm trying to get the book title which follows the path items.volumeInfo.title.
When I call valueForPath on the JSON object returned by the API and attempt to print it (the title), I end up printing:
Optional((
"A Dance with Dragons"
))
I can't seem to figure out how to actually get the string out of the printed optional. I tried as! String and jsonResult.valueForKeyPath("items.volumeInfo.title")!, but the first simply complained to me and the second only removed the optional and outside set of parentheses.
func getBookInfo(isbn: String) {
var url: String = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn;
var request: NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
println(jsonResult.valueForKeyPath("items.volumeInfo.title"))
//self.json.setValue(jsonResult.valueForKeyPath("items.volumeInfo.title")!, forKey: "title")
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
})
}
The response you get from the API is an array of titles.
I suggest using if let to unwrap the Optional value you get from KVC, and typecasting the result as a Swift array of Strings.
Swift 1
func getBookInfo(isbn: String) {
var url: String = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn
var request: NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary {
if let arrayOfTitles = jsonResult.valueForKeyPath("items.volumeInfo.title") as? [String] {
let titles = ", ".join(arrayOfTitles)
println(titles)
} else {
// error: no title found
}
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
})
}
getBookInfo("0553283685") // prints "Hyperion"
Swift 2
For this version we're using NSURLSession because NSURLConnection is now deprecated.
func getBookInfo(isbn: String) {
let urlString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn
if let url = NSURL(string: urlString) {
NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: {data, _, error -> Void in
if let error = error {
print(error.localizedDescription)
} else {
if let data = data,
jsonResult = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
arrayOfTitles = jsonResult.valueForKeyPath("items.volumeInfo.title") as? [String] {
let titles = arrayOfTitles.joinWithSeparator(", ")
print(titles)
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
}
}).resume()
}
}
getBookInfo("0553283685") // prints "Hyperion"
Swift 3
Same as Swift 2 with some syntax changes. I've also added the "authors" example, and I'm now using guard. Just for the sake of showing something different from the previous example.
func getBookInfo(isbn: String) {
guard let url = URL(string: "https://www.googleapis.com/books/v1/volumes?q=isbn:\(isbn)") else {
print("the url is not valid")
return
}
URLSession.shared().dataTask(with: url, completionHandler: {data, response, error -> Void in
guard error == nil else {
print(response)
print(error!.localizedDescription)
return
}
guard let data = data else {
print("no error but no data")
print(response)
return
}
guard let jsonResult = try? JSONSerialization.jsonObject(with: data, options: []) else {
print("the JSON is not valid")
return
}
if let arrayOfTitles = jsonResult.value(forKeyPath: "items.volumeInfo.title") as? [String] {
print(arrayOfTitles)
}
if let arrayOfAuthors = jsonResult.value(forKeyPath: "items.volumeInfo.authors") as? [[String]] {
print(arrayOfAuthors)
}
}).resume()
}
getBookInfo(isbn: "0553283685")

Get array of facebook albums in swift using Facebook SDK 4.1

I'm attempting to fetch an array of a users facebook albums via the new Facebook SDK 4.1 using the following Swift code:
func getAlbumList()
{
var FBAlbums = [String]()
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me?fields=albums", parameters: nil)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil)
{
// Process error
println("Error: \(error)")
}
else
{
println("fetched data: \(result)")
let graphData = result.valueForKey("data") as Array;
for obj:FBGraphObject in graphData{
let desc = obj.description;
println(desc);
let name = obj.valueForKey("name") as String;
println(name);
}
}
})
}
The FB SDK query is working ok as the result value contains all the data from facebook (it prints fine), however any attempt to actually turn this into an array is failling.
Using XCode 6.3 this gives the following errors:
let graphData = result.valueForKey("data") as Array; = 'AnyObject?' is not convertible to 'Array<T>'
for obj:FBGraphObject in graphData{ = Use of undeclared type 'FBGraphObject'
I can't seem to find any information about what has replaced FBGraphObject, or why I can't convert the result to an array.
Articles used as background (but out of date it seems):
Creating an Array of objects from the Facebook SDK in Swift
http://selise.ch/build-a-facebook-album-browser-using-swift/
Just change this line of your code:
let graphData = result.valueForKey("data") as Array;
To:
self.dict = result["data"] as! NSArray
This works for me retrieving user photos from facebook:
FBSDKGraphRequest(graphPath: "me/photos", parameters: ["fields": "id, name, source"]).startWithCompletionHandler({ (connection, result, error) -> Void in
if (error == nil){
self.dict = result["data"] as! NSArray
for item in self.dict { // loop through data items
if let urlString = item["source"]! {
let url = NSURL(string: urlString as! String)
let imageData = NSData(contentsOfURL: url!)
let image = UIImage(data: imageData!)
self.socialPhotoCollection.append(image!)
}
}
}
})
This is for getting all albums in a different way
Swift 3x:
FBSDKGraphRequest(graphPath: "/me/albums", parameters: ["fields":"id,name,user_photos"], httpMethod: "GET").start(completionHandler: { (connection, result, error) in
print(result!)
})

Resources