iOS Facebook Connect news feed - objective-c

I need to get the user news feed data.
Currently I'm using this:
[[FBManager defaultManager]getFBRequestWithGraphPath:#"me/home" params: andDelegate:self];
and then:
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]])
result = [result objectAtIndex:0];}
result gives me a bunch of data. But how do Extract these individually? Maybe the name and message for example??

I'd change from using requestWithGraphPath to requestWithMethodName.
Here's the sample code:
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:#"SELECT post_id, actor_id, message FROM stream WHERE filter_key = 'others '", #"query",
nil];
[facebook requestWithMethodName: #"fql.query"
andParams: params
andHttpMethod: #"POST"
andDelegate: self];
Then in the request didLoad method:
- (void)request:(FBRequest *)request didLoad:(id)result
{
if ([result isKindOfClass:[NSArray class]])
result = [result objectAtIndex:0];
friendID = [[result objectForKey:#"actor_id"]copy];
friendMsg = [[result objectForKey:#"message"]copy];
}
Facebook documentations on the iOS FB Connect SDK are very blend. It helps if you know a bit of SQL(fql) :)

Related

How to tag users in a photo using the Facebook iOS SDK?

I can't seem to work out how to tag users in a Facebook photo upload.
The documentation seems to suggest that you use an array, but the following code doesn't parse correctly (causes an application crash)
- (void)uploadImage:(UIImage *)img
withTags:(NSArray *)tags
{
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"msgstring", #"message",
img, #"picture",
nil];
if (tags) {
[params setObject:tags
forKey:#"tags"];
}
self.requestType = FBAssistantRequestImageUpload;
[self.facebook requestWithGraphPath:#"me/photos"
andParams:params
andHttpMethod:#"POST"
andDelegate:self];
}
It works fine without the tags. The array at the moment contains a single string with the identifier of the friend I wish to tag.
I assume I'm adding the tags incorrectly. I was hoping to avoid having to use the three-step method outlined here: Tag Friends in Facebook Photo Upload, as I believe that requires photos permission, which just posting the photo doesn't need.
here's the code I use to tag friends on photos:
NSMutableArray *tags = [[NSMutableArray alloc] init];
NSString *tag = nil;
if(self.selectedFriends != nil){
for (NSDictionary *user in self.selectedFriends) {
tag = [[NSString alloc] initWithFormat:#"{\"tag_uid\":\"%#\"}",[user objectForKey:#"id"] ];
[tags addObject:tag];
}
NSString *friendIdsSeparation=[tags componentsJoinedByString:#","];
NSString *friendIds = [[NSString alloc] initWithFormat:#"[%#]",friendIdsSeparation ];
[params setObject:friendIds forKey:#"tags"];
}

Objective C how to get a Facebook access token

I'm having some trouble pulling a Facebook access token from the web for a Facebook Feed App I'm writing. The problem isn't strictly related to gaining a Facebook token; this just frames the problem. When I go to https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=[APP_ID]&client_secret=[APP_SECRET], I am returned a token on a page that simply says:
access_token=464483653570261|cY9NHFBWCDJ9hSQfswWFg0FDZvw
How can I parse that from the webpage into my app? I'm relatively new to Objective C (and I've only got a year of basic coding experience), so I tried to use part of a method that I found online to get a JSON feed, combined with a simple parsing method, but it didn't work. The code is as follows:
id getToken = [self objectWithUrl:[NSURL URLWithString:#"https://graph.facebook.com/
oauth/access_token?grant_type=client_credentials&
client_id=464483653570261&
client_secret=55bb8395ed0293bf37af695f6cdaa1fb"]];
NSString *fullToken = (NSString *)getToken;
NSLog(#"fullToken: %#", fullToken);
NSArray *components = [fullToken componentsSeparatedByString:#"="];
NSString *token = [components objectAtIndex:1];
NSLog(#"token: %#", token);
Both of my NSLogs say that the respective Strings point to (null). I'm not really certain what I'm doing wrong, and I haven't had much luck finding answers on the internet, as I'm not sure what to call what I'm trying to do. I'd appreciate any help, or alternate methods, that you might have.
By the look of it, the value you're getting isn't JSON, it's just a string.
Try something like this:
NSURL * url = [NSURL URLWithString:#"https://graph.facebook.com/
oauth/access_token?grant_type=client_credentials&
client_id=464483653570261&
client_secret=55bb8395ed0293bf37af695f6cdaa1fb"]];
NSString * fullToken = [NSString stringWithContentsOfUrl: url];
NSLog(#"fullToken: %#", fullToken);
NSArray *components = [fullToken componentsSeparatedByString:#"="];
NSString *token = [components objectAtIndex:1];
NSLog(#"token: %#", token);
There is a more simple way of getting User's access_token using the ACAccountStore & ACAccountType. Check the Full Code Below:
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSDictionary *FBOptions = [NSDictionary dictionaryWithObjectsAndKeys:FACEBOOK_APP_ID, ACFacebookAppIdKey,#[#"email"],ACFacebookPermissionsKey, nil];
[accountStore requestAccessToAccountsWithType:accountType options:FBOptions completion:
^(BOOL granted, NSError *error) {
if (granted) {
NSArray *facebookAccounts = [accountStore accountsWithAccountType:accountType];
FBAccount = [facebookAccounts firstObject];
NSLog(#"token :%#",[[FBAccount credential] oauthToken]);
} else {
NSLog(#"error getting permission %#",error);
if([error code]== ACErrorAccountNotFound){
NSLog(#"Account not found. Please setup your account in settings app");
}
else {
NSLog(#"Account access denied");
}
}
}];

Photo Not Uploading on Check In Using Facebook iOS

So I'm creating an iPhone app that needs to be able to upload a photo when the user checks into a location using the Facebook Graph API.
Right now my code is this:
if (![delegate.facebook isSessionValid])
[delegate.facebook authorize:[NSArray arrayWithObjects:#"publish_stream", #"offline_access", #"publish_checkins", nil]];
parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:[placeDictionary objectForKey:#"id"] , #"place",
serialisedCoordinates, #"coordinates",
message, #"message",
pickedImage, #"picture",
#"Via the official REDACTED app", #"application", nil];
[delegate.facebook requestWithGraphPath:#"me/checkins" andParams:parameters andHttpMethod:#"POST" andDelegate:fbCheckInResultHandler];
Where 'pickedImage' is the UIImage returned from a UIImagePickerController.
Even when I pick an image (i.e., pickedImage != nil), no picture is uploaded when checked in. The check in appears on Facebook with the message, coordinates and app information, just no image.
Really hope someone can help.
Cheers,
Kiran
Here is the whole function that is being called when a checkin is made:
-(void)fbPostCheckInWithMessage:(NSString *)message andFriends:(NSArray *)friends {
if (![delegate.facebook isSessionValid]) {
NSLog(#"Session invalid");
[delegate.facebook authorize:[NSArray arrayWithObjects:#"publish_stream", #"offline_access", #"publish_checkins", nil]];
} else {
NSLog(#"Session valid");
}
NSMutableString *friendsIDString;
friendsIDString = [NSMutableString stringWithFormat:#"%#", [[friends objectAtIndex:0] userID]];
if ([friends count] > 1) {
for (User *f in taggedFriends) {
if (f != [taggedFriends objectAtIndex:0]) {
[friendsIDString appendString:[NSString stringWithFormat:#", %#", f.userID]];
}
}
}
NSLog(#"Tagged Friends: %#", friendsIDString);
SBJSON *jsonWriter = [SBJSON new];
NSMutableDictionary *locationDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:#"%f", userLocation.coordinate.latitude], #"latitude",
[NSString stringWithFormat:#"%f", userLocation.coordinate.longitude], #"longitude", nil];
NSString *serialisedCoordinates = [jsonWriter stringWithObject:locationDictionary];
NSData *pictureData = UIImagePNGRepresentation(pickedImage);
NSLog(#"picture: %#", pictureData);
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:[placeDictionary objectForKey:#"id"] , #"place",
serialisedCoordinates, #"coordinates",
pictureData, #"message",
pickedImage, #"picture",
#"Via the official REDACTED app", #"application", nil];
[delegate.facebook requestWithGraphPath:#"me/checkins" andParams:parameters andHttpMethod:#"POST" andDelegate:fbCheckInResultHandler];
}
I am using the friendsIDString to get the IDs of the friends the user with. I've removed this functionality from the example here because it was all commented out because I was trying to isolate what was causing the problem (which was the photo tagging). Just wanted to clear that up.
--UPDATE--
Here's how I'm setting pickedImage. I use the delegate methods from the UIImagePickerController:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
NSLog(#"Picked image");
pickedImage = [[UIImage alloc] init];
pickedImage = image;
[imagePickerController dismissModalViewControllerAnimated:YES];
}
You can upload photos to facebook using :- UIImagePNGRepresentation,UIImageJPEGRepresentation,etc based on type of image or imagewithdata from UIImage class..
NSData *yourImageData= UIImagePNGRepresentation(yourImage);
Initialize the dictionary :-
NSMutableDictionary *mutableDictWithParam= [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Your text", #"message", yourImageWithData, #"theSource", nil];
finally send post :-
[facebook requestWithGraphPath:#"/me/photos" andParams:mutableDictWithParam andHttpMethod:#"POST" andDelegate:self];
In you app i think you have not initialized your NSData object(pickedimage) ..else everything seems fine.
As Per Our Discussion You can use this to compress image:-
NSData* UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality);
NSData *compressedImage = UIImagePNGRepresentation(yourIMage, .5)//quality is ensured through second argument lies between o and 1

No results returned when doing Facebook Query

I'm trying to get a list of aid (album ids) using a Facebook Query.
What Works:
Running the query from the browser returns results, but when I run it using Facebook Connect no values are returned.
The problem I'm having is specific the album object, I get results when querying the user table.
The only real difference I can think of is when running from the browser a access_token parameter is included, running from browser without this returns nothing.
Authentication:
I am using OAuth to authenticate as outlined here: Mobile Apps - Getting Started
Do I need to include the access_token in the parameter list when doing a query?
The Code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
facebook = [[Facebook alloc] initWithAppId:#"<myAppId>"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:nil delegate:self];
}
NSArray* permissions = [[NSArray arrayWithObjects:
#"email", #"read_stream", nil] retain];
[facebook authorize:permissions delegate:self];
NSString *fql = [NSString stringWithFormat:#"SELECT aid FROM album WHERE owner=me()"];
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:fql, #"query", #"json", #"format", nil];
[facebook requestWithMethodName:#"fql.query" andParams:params andHttpMethod:#"GET" andDelegate:self];
return YES;
}
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0]; }
NSLog(#"didLoad() received result: %#", result);
}
Yes, you absolutely need to include the access_token field. We verify that the access token has access to the user_photos permission before allowing you access to that user's data.

Adding Objects from an Array into Core Data

So, for the past two days or so I've been struggling with something that should honestly be a simple task. Here's a little introduction on what I'm trying to achieve.
What I'm doing is utilising a web service of my own, sending a request and parsing the returned JSON with SBJSON. What I know want to accomplish with this parsed JSON is to insert it into Core Data.
I have built a object model already which looks like the following:
#import <CoreData/CoreData.h>
#interface Event : NSManagedObject
{
}
#property (nonatomic, retain) NSString * summary;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSDate * updated;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSDate * created;
#property (nonatomic, retain) NSString * ID;
#end
These are all built in regards to what is being parsed, I think I may have to change the NSDate's to NSStrings at a later date, but for now they are NSDates.
So, now to show you what is being parsed. The JSON returns the following.
[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"},
{"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"},
{"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]
What I am wanting to do is create an entity "Event" and each entity stores the respective values for that event. Easy, right? Obviously not for me.
What I have tried...
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
Yet this returns an error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSArrayI; value = (
Car,
"Premium Users",
"Welcome!"
).'
Any ideas or code samples would help. I really need to get this fixed, all dependent on how this is being stored.
EDIT
Here's how we build the request and parse the string returned.
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
EDIT
Just thought I'd let people know that I'm currently using the Resty RESTful framework to make my calls to my own API. I thought this was the best alternative and easiest way for myself to build a wrapper for it. Here is the full request.
Resty documentation.
-(void)pullNotes {
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:url parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
}
}];
}
EDIT
So, now that I have fixed the JSON issue and am grabbing the individual strings and such from each array, I'm having issues storing the parsed strings into Core Data.
I'll show you what I currently have.
[newNote ] is the name given to the Core Data entity in the header file of the following.
-(void)pullNotes {
UIApplication *app = [UIApplication alloc];
app.networkActivityIndicatorVisible = YES;
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray *notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
// newNote.created = [singleNote objectForKey:#"note created"]; Need to work on parsing these properly...
// newNote.updated = [singleNote objectForKey:#"note updated"]; Need to work on parsing these properly...
NSString *notetitle = [singleNote objectForKey:#"note title"];
NSString *notesummary = [singleNote objectForKey:#"note summary"];
NSString *noteid = [singleNote objectForKey:#"note id"];
NSString *notecontent = [singleNote objectForKey:#"note content"];
// NSDate *createdDate =
// NSDate *updatedDate =
// If appropriate, configure the new managed object.
[newNote setValue:notetitle forKey:#"title"];
[newNote setValue:notesummary forKey:#"summary"];
[newNote setValue:noteid forKey:#"ID"];
[newNote setValue:notecontent forKey:#"content"];
NSLog(#"value is %#", notetitle);
NSError *error = nil;
if (![newNote.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[tableView reloadData];
app.networkActivityIndicatorVisible = NO;
}
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
app.networkActivityIndicatorVisible = NO;
}
}];
}
#end
However, running this code doesn't actually store the strings into the Core Data entity. As you can see it isn't finalised, a lot of commented code, but the basis is there. ANYWAY, I'm curious as to whether or not it is how I actually implement this in the pulling of the notes itself from the RootViewController...
In viewDidLoad() I'm calling the following...
ntIndex = [IndexNotes alloc];
ntIndex.api_key = api_key;
ntIndex.tableView = self.tableView;
[ntIndex pullNotes];
[ntIndex release];
[self.tableView reloadData];
}
Any help would be great, I'd love to hear what others think the issue is. I don't get any errors with the above code, just nothing is inserted into the Core Data and in turn isn't displayed in my UITableView in RootViewController...
The first thing I would do is log what this line returns:
[object valueForKey:#"note title"]
You'll find it's not the string you're expecting, but is an array of note titles.
eg:
NSLog(#"value is %#", [object valueForKey:#"note title"]);
Then you'll either need to fix your JSON or change the way you parse it.
Edit:
So when I say fix your JSON, I'm no expert, but I think it should look like this:
{"result":[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]}
Then:
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
[singleNote objectForKey:"note title"] //this gives you the title of the current note your on
}
It's to do with the fact [object valueForKey:#"note title"] is returning an array.
You'll like want to insert something more like [[object valueForKey:#"note title"] objectAtIndex:1] to take an object out of the array. However working out what index you want to insert from the title array is the hardest part.
Tim
EDIT:
Having looked into some others responses its apparent it's returning all the titles in one object. There's something either incredibly funky going on with your JSON. A way around this would be to possibly for loop over your results set from your JSON request and using the index from this loop to insert the correct title.
eg:
int count;
for (count = 0; count < [[object valueForKey:#"note title"] count]; count++)
{
// Do your other insert stuff here
[newNote setValue:[[object valueForKey:#"note title"] objectAtIndex:count] forKey:#"title"];
}
again this is just a dirty example of what you could possibly do so solve this problem.