What goes wrong to access twitter timeline account? - ios

I tried the fallowing code to get access twitter timeline. It doesn't received any data from the server.What went wrong here?
ACAccount *twitterAccount=[arrayOfAccounts lastObject];
NSURL *requestURL=[NSURL URLWithString:#"http://api.twitter.com/1/statuses/user_timeline.json"];
NSMutableDictionary *parameters=[NSMutableDictionary new];
//[parameters setObject:#"100" forKey:#"count"];
//[parameters setObject:#"1" forKey:#"include_entities"];
SLRequest *post=[SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:parameters];
post.account=twitterAccount;
[post performRequestWithHandler:^(NSData *response, NSHTTPURLResponse *urlResponse, NSError *error) {
self.array=[NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
if(self.array.count !=0)
NSLog(#"%#",self.array);
else
NSLog(#"No Data Recived");
Thanks in advance.

Twitter has advice to use Version 1.1 not advice v1. In version 1.1 api https,So try to use this url https://api.twitter.com/1.1/statuses/user_timeline.json instated of this url http://api.twitter.com/1/statuses/user_timeline.json. This work's fine.

Those NSError objects the API gives you? Their purpose is to tell you what went wrong. Use them.
Your problem is that you don't know what happened because you just try to convert to JSON. That is what could have went wrong:
the request failed (e.g. network problem)
you are not authorized to do whatever you did
the data returned is not actually JSON
the JSON object is not an array (would have lead to a crash).
To write defensive code (and that's what you want if you want to release this thing to the public) you have to check each of these steps to figure out what went wrong, so you can act accordingly. Yes, that will take more code, but less code is not always the best choice.
Code with better error handling would more look like this. Note how it checks the result of each step that could go wrong:
[post performRequestWithHandler:^(NSData *response, NSHTTPURLResponse *urlResponse, NSError *error) {
if (response) {
// TODO: might want to check urlResponse.statusCode to stop early
NSError *jsonError; // use new instance here, you don't want to overwrite the error you got from the SLRequest
NSArray *array =[NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&jsonError];
if (array) {
if ([array isKindOfClass:[NSArray class]]) {
self.array = array;
NSLog(#"resulted array: %#",self.array);
}
else {
// This should never happen
NSLog(#"Not an array! %# - %#", NSStringFromClass([array class]), array);
}
}
else {
// TODO: Handle error in release version, don't just dump out this information
NSLog(#"JSON Error %#", jsonError);
NSString *dataString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#"Received data: %#", dataString ? dataString : response); // print string representation if response is a string, or print the raw data object
}
}
else {
// TODO: show error information to user if request failed
NSLog(#"request failed %#", error);
}
}];

Related

NSJSONSerialization json object leads to annoying empty XCode debug variables

I'm using NSJSONSerialization's JSONObjectWithData method to serialize json response data into a NSDictionary hierarchy, as part of my API handling in IOS. This works great. The long standing tedious part however is that when using the XCode debugger, the nested json data structure is not viewable in the variable watcher. This can best be seen in the photo at the end. The data is all accessible and navigable in the code, it just isn't for the debugger.
Is there any way to clean this up or serialize it better?
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error){
NSLog(#"Request Error: %#", [error localizedDescription]);
if(completionHandler != nil){
completionHandler(nil,error);
}
} else {
NSError *jsonerror = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonerror];
if(jsonerror) {
NSLog(#"JSON Serialize Error: %#", [jsonerror localizedDescription]);
if(completionHandler != nil){
completionHandler(nil,jsonerror);
}
} else {
if(completionHandler != nil){
completionHandler(json,nil); // usual successful json route
}
}
}
}];
Try using AFNeteorking for serialization.
https://github.com/AFNetworking/AFNetworking
It might help.
If not you can print what ever you need in the console part of the debugger using po.
po object
For example

iOS twitter API loadings more than 20 followers/following/tweets

I have a simple twitter client that I am using to display a users tweets, followers, and following.
For some reason the count parameter for user tweets is being ignored and it is always loading only 20 results.
Here is the code:
- (void)getUserTweets {
// 1. Create a variable for twitter
NSURL *feedURL = [NSURL URLWithString:#"https://api.twitter.com/1.1/statuses/user_timeline.json"];
// 2. Get AppDelegate reference
AppDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
// 3. Create NSDictionary for the TWR parameters
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: self.usernameToLoad, #"screen_name", #"true", #"include_user_entities", #"100", #"count", nil];
// 4. Create TWRequest, with parameters, URL & specify GET method
//TWRequest *twitterFeed = [[TWRequest alloc] initWithURL:feedURL parameters:parameters requestMethod:TWRequestMethodGET];
SLRequest *twitterFeed = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:feedURL parameters:params];
// 5. Specify twitter request's account to our app delegate's
twitterFeed.account = appDelegate.userAccount;
// Making the request
[twitterFeed performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
// Check if we reached the reate limit
if ([urlResponse statusCode] == 429) {
NSLog(#"Rate limit reached");
return;
}
// Check if there was an error
if (error) {
NSLog(#"Error: %#", error.localizedDescription);
return;
}
// Check if there is some response data
if (responseData) {
NSError *error = nil;
self.userTweets = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
}
});
}];
}
This will always return only 20 results, even if I set the count to something low like 1 or 2. Am I doing something wrong in defining my parameters?
Also, I am trying to load the users followers and following but I want to load a total of 200 if each, but again it is only loading 20.
From what the twitter API reads, It supplies automatic pagination and using the cursor parameter I can iterate through to load all of the data I want.
I am having a hard time figuring out exactly how this works. Here is my code for following (followers is identical with the exception of it calling a different API string)
- (void)getFriends {
// 1. Create a variable for twitter
NSURL *feedURL = [NSURL URLWithString:#"https://api.twitter.com/1.1/friends/list.json"];
// 2. Get AppDelegate reference
AppDelegate *appDelegate =[[UIApplication sharedApplication] delegate];
// 3. Create NSDictionary for the TWR parameters
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: self.usernameToLoad, #"screen_name", #"true", #"include_user_entities", nil];
// 4. Create TWRequest, with parameters, URL & specify GET method
//TWRequest *twitterFeed = [[TWRequest alloc] initWithURL:feedURL parameters:parameters requestMethod:TWRequestMethodGET];
SLRequest *twitterFeed = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:feedURL parameters:parameters];
// 5. Specify twitter request's account to our app delegate's
twitterFeed.account = appDelegate.userAccount;
// Making the request
[twitterFeed performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
// Check if we reached the reate limit
if ([urlResponse statusCode] == 429) {
NSLog(#"Rate limit reached");
return;
}
// Check if there was an error
if (error) {
NSLog(#"Error: %#", error.localizedDescription);
return;
}
// Check if there is some response data
if (responseData) {
NSError *error = nil;
NSDictionary *TWData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
self.userFriends = [TWData objectForKey:#"users"];
}
});
}];
}
I am not sure how to properly loop through because the twitter api returns the cursor value I need to go to the next data.
Any help would be great, I might just be missing some logic I can't quite put my finger on.
Thanks in advance!
Results are given in multiple "pages" of results can be navigated through using the next_cursor value in subsequent requests.
https://dev.twitter.com/docs/misc/cursoring
Fine, I too had the same problem in paging the tweet feeds, It never used to update "max_id" parameter, because its value was "NSNumber", Then i changed to to NSString then it worked perfectly fine for me, Cross check once again weather any objects other than NSString are used in the request

AFNetworking: Can't get the response string from AFHTTPRequestOperation

Anyone?): I'm having a problem that has made me scratch my head for the last 2 hours, and it most likely a very simple stupid thing I'm missing. I Keep getting a building error when I Call the response string from the operation # AFNetworking... Like there is NO SUCH PROPERTY....
Please Take a look at my code and Explain me what did I Mess up This time :p.. THanks :)
NSDictionary* paramDict = [NSDictionary dictionaryWithObjectsAndKeys:WebServicemd5Value, WebSermd5Variable, nil]
;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:webServiceURL]];
[httpClient defaultValueForHeader:#"Accept"];
[httpClient postPath:#"method" parameters:paramDict success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response data: %#", responseObject);
NSLog(#"Reponse String: %#", operation);
// Printing operation will show me the operation Dictionary, including the reponse field, // but when I Directly call operation.response, the Compiler won't Build, stating that // "Property not found for AFHTTPRequestOperation".... WEIRDEST THING EVER, right?
NSString* responseString = [NSString stringWithUTF8String:[responseObject bytes]];
//.. Rest o f my Code....
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", error);
}];
Hernan, if you expect an NSDictionary from a JSON response you should consider using AFJSONRequestOperation, because you get a JSON dictionary in your success callback. Anyway, if you want to get a dictionary from your responseObject, try to use the following code:
NSError *error = nil;
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(#"Error serializing %#", error);
}
NSLog(#"Dictionary %#", JSON);
I believe the response string is inside the "operation" object, so something like:
...
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", operation.responseString);
}];
While attempting to retrieve content from meetup.com api using AFNetworking (kudos to Mattt T. for a great framework, btw), ran into the same error - "The operation couldn't be completed. (Cocoa error 3840)". Realized that the issue I was having was with the response data containing a Swedish character 'Ø', resulting in the parsing error. The solution was to include the header 'Accept-Charset: utf-8' in the initialization of the AFNetworking client. Fixed!
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
[self setDefaultHeader:#"Accept-Charset" value:#"utf-8"];
return self;
}

Is it possible to do a retweet from within an app via API?

I'm making an iPhone app where I get all feeds of a certain user. Now I was wondering if it's possible to do a retweet when you push a button? I'm using the social framework. After some searching through the social framework API, I didn't found anything.
Apple's limited Twitter API doesn't seem to cover retweets.
To retweet in iOS you would need to use Twitter's API
It looks like you would need to send the POST request yourself and it would look something like
http://api.twitter.com/1/statuses/retweet/3962807808.json // Taken from API page.
I've also found this SO post, but there doesn't seem to be an accepted answer
How to implement RETWEET in ios 5?
Here's some sample code for retweeting from Cocoanetics
- (void)_retweetMessage:(TwitterMessage *)message
{
NSString *retweetString = [NSString stringWithFormat:#"http://api.twitter.com/1/statuses/retweet/%#.json", message.identifier];
NSURL *retweetURL = [NSURL URLWithString:retweetString];
TWRequest *request = [[TWRequest alloc] initWithURL:retweetURL parameters:nil requestMethod:TWRequestMethodPOST];
request.account = _usedAccount;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (responseData)
{
NSError *parseError = nil;
id json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&parseError];
if (!json)
{
NSLog(#"Parse Error: %#", parseError);
}
else
{
NSLog(#"%#", json);
}
}
else
{
NSLog(#"Request Error: %#", [error localizedDescription]);
}
}];
}
EDIT: Keab42 pointed out the link is for the Twitter API which will be deprecated early next year. Here's the updated API page. https://dev.twitter.com/docs/api/1.1/get/statuses/retweets/%3Aid

Getting tweets via TWRequest for a tableview

Ok, I'm pretty new to this and been struggling with what you guys may feel is quite an easy exercise. I have trawled high and low and cannot find a good tutorial or walkthrough on how to do this. Basically, I am using the code below to obtain tweets and I only want the 'text' part of the tweet. How do I extract it out of the NSDictionary in order to use the 'text' key in a tableview? I have tried [dict objectForKey:#"text"] but it does not work - 'dict' does not seem to contain a 'text' attribute. Thanks in advance for any help.
// Do a simple search, using the Twitter API
TWRequest *request = [[TWRequest alloc] initWithURL:[NSURL URLWithString:
#"http://search.twitter.com/search.json?q=iOS%205&rpp=5&with_twitter_user_id=true&result_type=recent"]
parameters:nil requestMethod:TWRequestMethodGET];
// Notice this is a block, it is the handler to process the response
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if ([urlResponse statusCode] == 200)
{
// The response from Twitter is in JSON format
// Move the response into a dictionary and print
NSError *error;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
NSLog(#"Twitter response: %#", dict);
}
else
NSLog(#"Twitter error, HTTP response: %i", [urlResponse statusCode]);
}];
Yes there is an objectForKey#"text" but it is an array which means that every entry (tweet) has text (and several other attributes). So we've to loop through the tweets to get FOR every tweet the text.
In your .h file
NSMutableArray *twitterText;
In your .m file
Do this somewhere in viewdidload
twitterText = [[NSMutableArray alloc] init];
And now we can loop through your results. Paste this code where you've NSLog(#"Twitter response: %#", dict);
NSArray *results = [dict objectForKey#"results"];
//Loop through the results
for (NSDictionary *tweet in results)
{
// Get the tweet
NSString *twittext = [tweet objectForKey:#"text"];
// Save the tweet to the twitterText array
[twitterText addObject:(twittext)];
And for your cells in your tableView
cell.textLabel.text = [twitterText objectAtIndex:indexPath.row];
I think that should be working.

Resources