Facebook iOS SDK & Swift - How do I create dependent batch requests? - ios

I'm trying to figure out how to compose FB Graph API requests (FB SDK 4.0 and Swift) when the second (child) request is dependent on the first (parent) request. Specifically I would like to get a user's albums and each album's cover photo.
me/albums?fields=name,cover_photo <-- Get user albums request
/888474748 <-- Get cover photo request
The documentation is very vague regarding this and API docs for FBSDKGraphRequestConnection mention that method addRequest:completionHandler:batchParameters: can accept parameters such as "name" and "depends_on". This appears to be the method I'm looking for but I can find an example of its use in Obj-C or Swift.
Should it look something like this? Thanks!
let albumRequest = FBSDKGraphRequest(graphPath: "me/albums?fields=name,cover_photo", parameters: nil)
let albumCoverRequest = FBSDKGraphRequest(graphPath: "cover_photo_id", parameters: nil) //what should this look like? jsonpath?
let graphConnection = FBSDKGraphRequestConnection()
graphConnection.addRequest(albumRequest, completionHandler: { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if(error != nil){
println(error)
}else{
}
},batchParameters: ["name" : "albums"])
graphConnection.addRequest(albumRequest, completionHandler: { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if(error != nil){
println(error)
}else{
}
},batchParameters: ["depends_on" : "albums"]) //should this be some jsonpath expression?

Got it figured out.
let albumRequest = FBSDKGraphRequest(graphPath: "me/albums?fields=name,cover_photo", parameters: nil)
let albumCoverRequest = FBSDKGraphRequest(graphPath: "?ids={result=albums:$.data.*.cover_photo}", parameters: nil) // use jsonpath syntax to "inject" parent results into "child" request
let graphConnection = FBSDKGraphRequestConnection()
graphConnection.addRequest(albumRequest, completionHandler: { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if(error != nil){
println(error)
}else{
println(result)
}
},batchParameters: ["name" : "albums"]) //Set "parent" batch alias
graphConnection.addRequest(albumCoverRequest, completionHandler: { (connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
if(error != nil){
println(error)
}else{
println(result)
}
},batchParameters: ["depends_on" : "albums"]) //depend on parent batch alias
graphConnection.start()

Related

From FBSDKGraphRequest to Storyboard

i'm total beginner in coding, but i have a big question :)
I dont know how to get information to display on Main Storyboard form FBSDKGraphRequest.
What i should do next to get picture to Storyboard? I hope someone can help me :)
Using Swift 3, Xcode 8
Facebook login is working and code is:
func getFBUserData(){
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
self.dict = result as? [String : AnyObject]
print(result!)
print(self.dict)
}
})
}
I see it as four steps -- my apologies to you if you already know some of this.
Drag an UIImageView from the object library in interface builder to a view in your storyboard.
Connect the UIImageView to your code as an IBOutlet and name it. Do this by control dragging from your new UIImageView to your code, and then in the popup specify an outlet and name the UIImageView. In my case I named it 'facebookPicture'
Get the URL for the image from the FaceBook result. The following sample code drills down into the result dictionary step by step. There are many ways to shorten this.
#IBOutlet var facebookPicture: UIImageView!
func getFBUserID(){
if((FBSDKAccessToken.current()) != nil) {
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).start(
completionHandler: {
[weak self] (connection, result, error) -> Void in
guard let strongSelf = self else { return }
if let error = error {
print("Failed to download FB user with error:. \(error)")
}
if (error == nil) {
let resultDictSwift = result as! Dictionary<String, Any>
if let picture = resultDictSwift["picture"] as? Dictionary<String, Any> {
if let pictureData = picture["data"] as? Dictionary<String, Any> {
if let pictureURL = NSURL(string: (pictureData["url"] as? String)! ) {
strongSelf.downloadImage(url: pictureURL as URL)
}
}
}
print(result!)
let FBID = resultDictSwift["id"]
strongSelf.facebookID = FBID as! String?
print("User FB id: \(strongSelf.facebookID!)")
}
})
}
}
Download the image from the URL location. The following does this asynchronously and uses a previous stack overflow answer here When the download is complete, it sets the result of the download to be the image in your UIImageView
func getDataFromUrl(url: URL, completion: #escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}.resume()
}
func downloadImage(url: URL) {
print("Download Started")
getDataFromUrl(url: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
DispatchQueue.main.async() {
self.facebookPicture.image = UIImage(data: data)
}
}
}
I hope this helps!
In Swift 3
#IBAction func btnFacebookTapped(_ sender: UIButton)
{
let loginManager = FBSDKLoginManager()
loginManager.logIn(withReadPermissions: ["user_about_me", "email" , "user_birthday","user_hometown"], from: self) { (loginResult, error) in
if error != nil
{
self.showalert(strMessage: (error?.localizedDescription)!)
}
else
{
if loginResult?.grantedPermissions == nil
{
self.showalert(strMessage: "Login Permissions not granted")
return
}
if (loginResult?.grantedPermissions.contains("email"))!
{
self.getFBUserData()
}
}
}
}
func getFBUserData()
{
FBSDKGraphRequest.init(graphPath: "me?fields=id,name,email,first_name,last_name,cover,picture.type(large),gender,birthday,hometown", parameters: nil).start(completionHandler: { (connection , result , error ) in
if(error == nil){
DispatchQueue.main.async {
let dictionary = result as! NSDictionary
print(dictionary)
print("Name : \(dictionary.value(forKey: "name")!)")
print("FB ID : \(dictionary.value(forKey: "id")!)")
}
}else{
self.showalert(strMessage: "Somthig Went Wrong..!")
}
})
}

iOS facebook graph api comments

Is there way to fetch facebook comments with graph api without logging. When user is logged in comments can be fetch without problem, first I fetch user comment box object from web and after that make second request with id of comment box. If user is logged out in first request completition handler returns error The operation couldn’t be completed. (com.facebook.sdk.core error 8.)
let request = FBSDKGraphRequest(graphPath: "http://testapi.club/test.php", parameters: nil, HTTPMethod: "GET")
request.startWithCompletionHandler { (connection, result, error) in
if error == nil {
print(result)
let og_object = (result as! Dictionary<String, AnyObject>)["og_object"]
let objecId = (og_object as! Dictionary<String, AnyObject>)["id"]
let requestForComments = FBSDKGraphRequest(graphPath: "/\(objecId!)/comments", parameters: ["summary": "true","filter": "toplevel", "order":"chronological"], HTTPMethod: "GET")
requestForComments.startWithCompletionHandler({ (connection, result, error) in
if error != nil {
print(error.description)
}else {
print(result)
}
})
}else{
print(error.localizedDescription)
}
}

Getting values from Facebook FBSDK iOS 4.x (with Swift)?

How do I make all of the functions wait for a little before they access the facebookData variable? Since the network call is asynchronous, facebookData is being accessed before it is getting the values from the Facebook.
Please find the below code from information.
func graphRequestToReturnUserData(graphParameters: Dictionary<String, String>) {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: graphParameters)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil) {
print("Error: \(error.localizedDescription)") /*Error Handling*/
}else {
self.facebookData = result as! NSDictionary
}
})
}
I don't want to invoke the function like this :-
if ((error) != nil) {
print("Error: \(error.localizedDescription)") /*Error Handling*/
}else {
self.facebookData = result as! NSDictionary
self.printFacebookData()
}
})
}
func printFacebookData() {
print(self.facebookData)
}
Since I have found a solution that is working good in my situation, I am going to post it here for more to read, and possibly comment on it to improve further.
The simple solution here would be to use the property observer and call a function soon the property is changed. No need to mess up with the threads, or use of semaphores.
The solution code now looks like this: -
class facebookGraphRequest {
static var facebookData = NSDictionary()
//Property Observer, willSet-didSet
var facebookD = NSDictionary() {
didSet {
facebookGraphRequest.facebookData = facebookD //Assigning values to the static class variable
facebookUserSignUpLogIn().checkUserExistsOrNot() //Calling a function from the other class
}
}
//Mark: GraphRequestForFetchingUserData
func graphRequestToReturnUserData(graphParameters: Dictionary<String, String>) {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: graphParameters)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if ((error) != nil) {
print("Error: \(error.localizedDescription)") //Error Handling
} else {
self.facebookD = result as! NSDictionary
}
})
}
}
Here, the first part is the property observer (willSet-didSet), and then the GraphAPI call for getting the user data. Soon the facebookD variable is set to a value; the function checkUserExistsOrNot() is called from the class facebookUserSignUpLogIn for further actions.

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)
}

Passing parameters for posting an item to Facebook

I have a code for post to Facebook but in parameters I have to add my own but its not working for me.
I have these 3 things to post my Facebook i.e. title, description, date time.
let notSureItem = NotSureItem()
notSureItem.title = self.textField.text!
notSureItem.textDescription = self.textAreaDescription.text!
notSureItem.dateTime = self.dateTime
I have this code for posting to Facebook.
if (FBSDKAccessToken.currentAccessToken() != nil){
if FBSDKAccessToken.currentAccessToken().hasGranted("publish_actions") {
FBSDKGraphRequest(graphPath: "me/feed", parameters: ["message": "hello"], HTTPMethod: "POST").startWithCompletionHandler({
(connection, result, error) -> Void in
if !(error != nil) {
NSLog("Post id:%#", result["id"])
}
})
}
}
In parameters I had passed a message which is successfully post on Facebook but if I had to pass parameters which I had stated above how to do that.
If anyone can help thanks a lot.
This solved my problem. Simply passed as string and its work.
if (FBSDKAccessToken.currentAccessToken() != nil){
if FBSDKAccessToken.currentAccessToken().hasGranted("publish_actions") {
FBSDKGraphRequest(graphPath: "me/feed", parameters: ["message": "\(self.textField.text!)\n \(self.textAreaDescription.text!)\n \(self.dateTime)"], HTTPMethod: "POST").startWithCompletionHandler({
(connection, result, error) -> Void in
if !(error != nil) {
NSLog("Post id:%#", result["id"])
}
})
}
}

Resources