Objective-c facebook graph api pagination - ios

I'm developing an iOS app that includes a facebook feed of a users wall. Using the graph api with the following URL:
feedURL = [NSString stringWithFormat:#"https://graph.facebook.com/%#/feed?
access_token=%#&since=%#&until=%#",kFaceBookID,FBSession.activeSession.accessToken,
[dateRange objectForKey:#"since"], [dateRange objectForKey:#"until"]];
I get back data that only one result and a dictionary entry for paging. When I do a NSURLRequest with the "next" URL I get back 0 results. If I cut and paste that same URL into a web browser I get back 25 results. Any ideas on why?
Here is the code I am using:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *nextPageURL;
NSError *jsonError;
if (!jsonError) {
NSDictionary *rDict = [NSJSONSerialization JSONObjectWithData:_postData
options:0
error:&jsonError];
nextPageURL = [[rDict objectForKey:#"paging"]objectForKey:#"next"];
NSArray *rArray = [rDict objectForKey:#"data"];
DLog(#"Posts Dictionary = %#\n\n",rDict);
for (NSDictionary *rPost in rArray) {
FBPost *post = [[FBPost alloc]initFBPostWithDictionary:rPost];
[feedsArray addObject:post];
}
}
else
{
ALog(#"json error = %#",[jsonError localizedDescription]);
[activity stopAnimating];
NSString *errorMessage = [NSString stringWithFormat:#"Facebook status request failed with error: %#\nCheck your network connection and try again later",[jsonError localizedDescription]];
[self quit:errorMessage];
}
[feedsTable reloadData];
if (nextPageURL && [feedsArray count] < 30) {
DLog(#"Next Feed URL = %#",nextPageURL);
NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:nextPageURL]];
if (![[NSURLConnection alloc] initWithRequest:request delegate:self]) {
ALog(#"Connection failed for request: %#",request);
}
}
}

I am answering my own question as I took another look at the entire logic and completely changed my approach to use [FBRequestConnection...] instead. Here is the code if anyone is interested. Note that I fetch one weeks worth of feed messages at a time to improve the tableview performance.
- (void) fetchFBFeedsForDateRange:(NSDictionary *)dateRange;
{
_postData = [[NSMutableData alloc]init];
//since, until is a decremented one week at a time date range.
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
[dateRange objectForKey:#"since"], #"since",
[dateRange objectForKey:#"until"], #"until",
nil];
NSString *gPath = [NSString stringWithFormat:#"%#/feed",kFaceBookID];
[FBRequestConnection startWithGraphPath:gPath
parameters:params
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSArray *rArray = [result objectForKey:#"data"];
//DLog(#"Posts Array = %#\n\n",rArray);
for (NSDictionary *rPost in rArray) {
FBPost *post = [[FBPost alloc]initFBPostWithDictionary:rPost];
if (post.type) {
if (!post.skip) {
[feedsArray addObject:post];
}
}
}
[feedsTable reloadData];
if ([feedsArray count] < kFaceBookMaxPostsToDisplay) {
[self performSelector:#selector(fetchPreviousWeek)];
}
else
{
[activity stopAnimating];
}
}
else
{
[activity stopAnimating];
NSString *errorMessage = [NSString stringWithFormat:#"Facebook status request failed with error: %#\nCheck your network connection and try again later",[error localizedDescription]];
[self quit:errorMessage];
}
}];
}

Related

How can I make a request to aws cloudsearch using the AWS iOS SDK?

I have a client that runs their search functionality on their website through cloudsearch. I have been going through the documentation for days, and haven't been able to make a successful search request. I created an NSMutableRequest object, and am running that request through the AWSSignature method [signature interceptRequest:request]; but my task.result is coming back (null).
Here is my code:
AWSTask *task = [signature interceptRequest:request];
[task continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {
NSLog(#"task.result fromSearch:%#", task.result);
NSData *responseData = task.result;
NSString* newStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"newStr:%#", newStr);
NSLog(#"task.error:%#", task.error);
return nil;
}];
Am I on the right track, or is there a better way to do this through the aws iOS sdk?
To put a little more flesh on the bones of Robert's comment, I did it with some help from AFNetworking like so:
#import <AWSCore/AWSSignature.h>
#import <AWSCore/AWSService.h>
#import <AWSCore/AWSCategory.h>
#import <AWSCore/AWSCredentialsProvider.h>
#import <AWSCore/AWSTask.h>
#import "AFNetworking.h"
- (void)viewDidLoad {
[super viewDidLoad];
self.queue = [[NSOperationQueue alloc] init];
}
- (void)performSearch {
AWSAnonymousCredentialsProvider* credentialsProvider = [[AWSAnonymousCredentialsProvider alloc] init];
NSString* searchHost = #"<CloudSearchEndPoint>.eu-west-1.cloudsearch.amazonaws.com";
NSString* query = [self.searchTerms aws_stringWithURLEncoding];
NSURL* searchURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://%#/2013-01-01/search?q=%#", searchHost, query]];
AWSEndpoint* endpoint = [[AWSEndpoint alloc] initWithURL:searchURL];
AWSSignatureV4Signer* signer = [[AWSSignatureV4Signer alloc] initWithCredentialsProvider:credentialsProvider endpoint:endpoint];
NSMutableURLRequest* mutableRequest = [[NSMutableURLRequest alloc] initWithURL:searchURL];
AWSTask* task = [signer interceptRequest:mutableRequest];
[task continueWithBlock:^id(AWSTask* _Nonnull t) {
if (t.error) {
NSLog(#"Error: %#", t.error);
} else if (t.completed) {
NSLog(#"Result is %#", t.result);
}
AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:mutableRequest success:^(NSURLRequest* request, NSHTTPURLResponse* response, id JSON) {
NSLog(#"Success fetching results!");
if (JSON) {
NSDictionary* hitsContainer = [JSON objectForKey:#"hits"];
NSArray* hits = [hitsContainer objectForKey:#"hit"];
NSMutableArray* allResults = [[NSMutableArray alloc] initWithCapacity:hits.count];
for (NSDictionary* hit in hits) {
NSDictionary* fields = [hit objectForKey:#"fields"];
[allResults addObject:fields];
}
self.searchResults = allResults;
[self.tableView reloadData];
}
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Failure fetching search results :-( %#", error);
}
];
[self.queue addOperation:operation];
return nil;
}];

Google Place Search API in IOS

I have implemented the google place search API in IOS and enabled the API in the developer console and used the below code but its shows error that "This IP, site or mobile application is not authorized to use this API key. Request received from IP address 122.173.223.114, with empty refer"
After regenerate the API key its shows API key is expired and after sometime its shows the same above errors. Please help someone.
-(void) queryGooglePlaces: (NSString *) googleType {
// Build the url string to send to Google. NOTE: The kGOOGLE_API_KEY is a constant that should contain your own API key that you obtain from Google. See this link for more info:
// https://developers.google.com/maps/documentation/places/#Authentication
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%#&types=%#&sensor=true&key=%#", appDel.objLocationManager.location.coordinate.latitude, appDel.objLocationManager.location.coordinate.longitude, [NSString stringWithFormat:#"%i", appDel.currenDist],googleType, kGOOGLE_API_KEY];
//Formulate the string as a URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
if (responseData==nil) {
}else{
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
NSArray* places = [json objectForKey:#"results"];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
}
I did it with use of AFNetworking class Try this one,
#define kGoogleAutoCompleteAPI #"https://maps.googleapis.com/maps/api/place/autocomplete/json?key=%#&input=%#"
-(void)getAutoCompletePlaces:(NSString *)searchKey
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// set request timeout
manager.requestSerializer.timeoutInterval = 5;
NSString *url = [[NSString stringWithFormat:kGoogleAutoCompleteAPI,GoogleDirectionAPI,searchKey] stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSLog(#"API : %#",url);
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"JSON: %#", responseObject);
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSDictionary *JSON = responseObject;
predictions = [NSMutableArray array];
// success
AutomCompletePlaces *places = [AutomCompletePlaces modelObjectWithDictionary:JSON];
[arrSuggestionData removeAllObjects];
if (!arrSuggestionData) {
arrSuggestionData = [NSMutableArray array];
}
for (Predictions *pred in places.predictions)
{
[arrSuggestionData addObject:pred.predictionsDescription];
}
[self.Tbl_suggestion reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}];
}

How to get all friends from user's facebook account using facebook SDK ( iOS )?

I got one sample code (iOS) in which I am getting all user's friends (App Id = 377766775651612) but when I using own created app id (app id 707496825976004), I am getting the list of friends who are using my app.
I want all friends
Please help me
Thanks in advance
This is not possible with Graph API version 2.0.
This is not possible with Graph API version 2.0. Any app made after april 2014 will use 2.0. For more details, see this answer:
Get facebook friends with Graph API v.2.0
-(IBAction)permit:(id)sender
{
if ( [facebook isEqualToString:#"yes"])
{
UIAlertView *Alert = [[UIAlertView alloc] initWithTitle: #"Status!"
message: #"Please Log in first"
delegate: self
cancelButtonTitle: #"Ok" otherButtonTitles: nil];
[Alert show];
}
else
{
[self requestPermissionAndPost];
}
}
- (void)requestPermissionAndPost {
[FBSession.activeSession requestNewPublishPermissions:[NSArray arrayWithObjects:#"publish_actions",#"publish_stream",#"friends_birthday", nil]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error && [FBSession.activeSession.permissions indexOfObject:#"publish_actions"] != NSNotFound) {
[self getFriends];
} else if (error) {
if ([FBErrorUtility errorCategoryForError:error] != FBErrorCategoryUserCancelled) {
NSLog(#"error %#",error);
}
}
}];
}
-(void)getFriends
{
[self addMBProgress];
NSString *accsstoken=[[[FBSession activeSession]accessTokenData]accessToken];
NSString *abcd=[NSString stringWithFormat:#"https://graph.facebook.com/me/friends?fields=id,name,picture,birthday,location,email&access_token=%#",accsstoken];
NSURL *url = [NSURL URLWithString:abcd];
NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL: url];
[request1 setURL:url];
[request1 setHTTPMethod:#"GET"];
NSError *error;
NSURLResponse *response;
urlDataaa = [NSURLConnection sendSynchronousRequest:request1 returningResponse:&response error:&error];
if (urlDataaa!=nil)
{
if(NSClassFromString(#"NSJSONSerialization"))
{
NSError *error = nil;
id object = [NSJSONSerialization
JSONObjectWithData:urlDataaa
options:0
error:&error];
if(error)
{
}
if([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *results = object;
NSLog(#"results..:%#",results);
[self removeMBProgress];
venues = [results objectForKey:#"data"];
NSLog(#"birthday..%#",venues);
}
}
}
[venues enumerateObjectsUsingBlock:^(NSDictionary *dict,NSUInteger idx,BOOL *stop)
{
NSString *namess = [dict objectForKey:#"name"];
[name addObject:namess];
if ([dict objectForKey:#"birthday"]) {
NSString *birthdayss = [dict objectForKey:#"birthday"];
[birthday addObject:birthdayss];
}
else
{
[birthday addObject:#"No Birthday"];
}
}
];
NSString *query1 = [NSString stringWithFormat:#"DELETE from userdata"];
[[DBManager sharedDatabase]executeQuery:query1];
NSLog(#"query1:%#",query1);
userdata = [[DBManager sharedDatabase]userdata:#"select * from userdata"];
NSLog(#"userdata...%#",userdata);
for (int i=0; i<[name count]; i++)
{
NSString *namesss =[name objectAtIndex:i];
NSString *datesss =[birthday objectAtIndex:i];
NSString *query1 = [NSString stringWithFormat:#"INSERT INTO userdata (name,date) VALUES (\"%#\",\"%#\")",namesss,datesss];
NSLog(#"query1:%#",query1);
[[DBManager sharedDatabase]executeQuery:query1];
}
userdata = [[DBManager sharedDatabase]userdata:#"select * from userdata"];
NSLog(#"userdata...%#",userdata);
[userdata addObjectsFromArray:manualdata];
[tempSearchData removeAllObjects];
[tempSearchData addObjectsFromArray:userdata];
NSLog(#"tempSearchData..%#",tempSearchData);
[friendlist reloadData];
}
From Facebook sdk version 2.0 onwards, they changing the response like that(getting the list of friends who are using my app).I think from a particular date onwards its behave like that.if u register a new app in developer site ,it may behave like that only.

authorizeRequest oAuth not called from another class?

I'm currently using Oauth2SampleTouch by Google, so people can log-in with their google accounts into my app. However whenever I call a method from The SampleRootViewController it doesn't go through the authorizeRequest method (only if I call it from another class.).
Here's the method in SampleRootViewController that I'm calling form another class.(the user is already logged in by this time)
-(NSString *)hasLikedVideo:(NSString *)videoID {
liked = #"NULL";
NSString *clientID = #"myClientID";
NSString *clientSecret = #"myClientSecret";
self.auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:clientID
clientSecret:clientSecret];
NSString *urlStr = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/videos/getRating?id=%#&key=AIzaSyB437bMtpbJh-OrkieCDRtYLe6L1Ijb3Ww", videoID];
NSLog(#"URL FOR LIKE : %# auth:(%#)", urlStr, self.auth);
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"stage 1");
[self.auth authorizeRequest:request
completionHandler:^(NSError *error) {
if (error == nil) {
// the request has been authorized
NSLog(#"ERROR LOADING AUTH 1 : %#", [error description]);
} else {
NSLog(#"ERROR LOADING AUTH 2 : %#", [error description]);
}
NSLog(#"stage 2");
NSString *output = nil;
if (error) {
output = [error description];
NSLog(#"ERROR FROM LOADING LIKE INFO : %#", output);
} else {
NSLog(#"stage 3");
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
[self displayAlertWithMessage:output];
if (data) {
// API fetch succeeded
NSLog(#"stage 32");
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
// NSLog(#"%#", data);
[self displayAlertWithMessage:output];
} else {
NSLog(#"stage 34");
// fetch failed
output = [error description];
[self displayAlertWithMessage:output];
}
}
NSData* json = [output dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *allCourses = [NSJSONSerialization
JSONObjectWithData:json
options:kNilOptions
error:&error];
NSArray *monday = allCourses[#"items"];
for ( NSDictionary *theCourse in monday )
{
liked = theCourse[#"rating"];
NSLog(#"LIKE INSIDE ARRAY : %#", theCourse[#"rating"]);
}
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
}];
NSLog(#"stage 4");
return liked;
}
The method runs because I can see it log the string, however it doesn't go through the authorizeRequest, it doesn't even print out the error messages. HOWEVER if my viewController is SampleRootViewController and I call the method from itself it works.
So basically
TestViewcontroller calls a method in SampleRootViewController -> doesn't go through authorizeRequest.
SampleRootViewController calls a method in SampleRootViewController (from itself) -> goes through authorizeRequest and works.
EDIT:
I found out what I was doing "wrong"
I was calling the method like this in background
[self performSelectorInBackground:#selector(getAuthDetails) withObject:nil];
instead of
[self getAuthDetails];

My code for paging through Twitter friends using recursion not working - iOS

I'm trying to page through a user's twitter friends using cursors. Since you get 20 at a time along with a next cursor, I thought perhaps recursion was the best way to handle this. However, I believe because I'm using completion handler blocks, it isn't working correctly. I keep getting just two pages of friends (40), and it returns.
- (void)fetchTwitterFriendsForCrush:(Crush*)crush
fromCursor:(NSString*)cursor
usingManagedObjectContext:(NSManagedObjectContext*)moc
withSender:(id) sender
usingCompletionHandler:(void(^)())completionHandler
{
// twitter returns "0" when there are no more pages to receive
if (([cursor isEqualToString:#"0"]) || (cursor == nil)) {
completionHandler();
return;
}
NSString *urlString =
[NSString stringWithFormat:#"https://api.twitter.com/1.1/friends/list.json?cursor%#skip_status=1", cursor];
NSURL *requestURL = [NSURL URLWithString:urlString];
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter
requestMethod:SLRequestMethodGET
URL:requestURL
parameters:nil];
request.account = self.twitterAccount;
[request performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (error) {
NSLog(#"Error getting twitter friends = %#", error);
}
if (responseData) {
NSError *jsonError;
NSString *nextCursor = nil;
NSMutableArray *friendsArray = [NSMutableArray arrayWithCapacity:100];
NSDictionary *friendsDictionary =
[NSJSONSerialization JSONObjectWithData:responseData
options:0
error:&jsonError];
if ([friendsDictionary valueForKey:#"next_cursor_str"]) {
nextCursor = [friendsDictionary valueForKey:#"next_cursor_str"];
}
if ([friendsDictionary valueForKey:#"users"]) {
[friendsArray addObjectsFromArray:[friendsDictionary valueForKey:#"users"]];
}
for (NSDictionary *singleFriend in friendsArray) {
NSString *twitterID = [singleFriend valueForKey:#"id_str"];
NSString *name = [singleFriend valueForKey:#"name"];
NSString *screenName = [singleFriend valueForKey:#"screen_name"];
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^(void) {
// update model
TwitterFriend *newTwitterFriend =
[TwitterFriend twitterFriendWithTwitterID:twitterID
forCrush:crush
usingManagedObjectContext:moc];
newTwitterFriend.name = name;
newTwitterFriend.screenName = screenName;
});
}
[self fetchTwitterFriendsForCrush:crush
fromCursor:nextCursor
usingManagedObjectContext:moc
withSender:self
usingCompletionHandler:nil];
}
}];
}
And the method that calls it:
[self.twitterNetwork fetchTwitterFriendsForCrush:self.crush fromCursor:#"-1" usingManagedObjectContext:self.managedObjectContext withSender:self usingCompletionHandler:^{
//
[self reloadData];
}];
UPDATE: It appears that I'm receiving the same next_cursor data on every request. Has anyone experienced this? Or do you see anything in this code that would cause that?
I found that a more complex way is better. You may use https://api.twitter.com/1.1/friends/ids.json? to get your friends ids list. Then using 1.1/users/lookup.json you may get the full info for users. I wrote a small helper to drill down user friends with SLRequest (#iOS6) https://github.com/ArchieGoodwin/NWTwitterHelper

Resources