AFJSONRequestSerializer POST JSON Array - objective-c

I am trying to post to an API that is expecting a JSON array as input, for example:
[
{
"token": "bd3",
"display_order": 0
}
]
I am unable to get AFJSONRequestSerializer to produce this, my code to create the params :
NSDictionary *campParams = #{#"token" : #"bd3", #"display_order" : #"0" };
NSArray *arr = [NSArray arrayWithObject:campParams];
NSDictionary *final = [NSDictionary dictionaryWithObject:arr forKey:#""];
Which creates the JSON as:
{"":[{"token":"bd55","display_order":"0"}]}
How can I modify my code to get the proper JSON output? I am creating a second dictionary as the AFHTTPRequestOperationManager accepts parameters as a dictionary, not an array.
[manager PUT:url parameters:final success:^(AFHTTPRequestOperation *operation, id responseObject) {
//done
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];

Don't add the last dictionary operation, the questions shows that a JSON array is expected..
NSArray * jsonArray = #[ #{ #"token" : #"bd3", #"display_order" : #"0" } ];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArray options:0 error:&error];
NSLog(#"jsonData as String: %#", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
Output:
jsonData as String: [{"token":"bd3","display_order":"0"}]
There is a possibility that the last argument should be a number, not a string:
NSArray * jsonArray = #[ #{ #"token" : #"bd3", #"display_order" : #0 } ];
producing:
jsonData as String: [{"token":"bd3","display_order":0}]
which better matches your initial JSON example.
Here is an example but not using AFNetworking because I am not conversant in it:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPBody:jsonData];
[request setHTTPMethod:#"POST"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"Error: %#", connectionError);
}
else {
NSLog(#"data as String: %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
}];
Note: By all means use AFNetworking, it is great! I just know the older OSX/iOS methods by heart and I did not have a test project that already had AFNetworking installed.

My solution was to simply change the request serializer, I was not aware that it was not using JSON by default, so I changed it and now it works.

Related

Convert NSData from NSURLSession to JSON

I am aware that there are many similar SO questions that have a similar title to mine. I have checked them out and am still running into this problem.
I am trying to access an API that returns a string that should/could be formatted as JSON.
To retrieve this string as convert the string to JSON I'm using (unsuccessfully) this code:
NSError *error;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#",responseString);
NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSLog(#"%#",[json objectForKey:#"ID"]);
NSLog(#"Json: %#",json);
}];
[task resume];
The NSLog(#"Response:...) returns a string that when I enter it into this website: http://jsonviewer.stack.hu confirms that the string is valid JSON.
Both NSLog's that are supposed to return a JSON value come back null.
What iv'e tried:
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&error];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
I have also now tried:
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary *jsonObject;
NSError *err = nil;
#try
{
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
}
#catch (NSException *exception)
{
NSLog( #"Exception caught %#",exception);
}
NSDictionary *info = jsonObject;
NSLog(#"Json: %#",info);
}];
[task resume];
What am I doing wrong here? How can I get a NSDictionary (JSON) result.
Your main issue:
If you read the error parameter of +JSONObjectWithData:options:error:, it will tell you this:
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start
with array or object and option to allow fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array or
object and option to allow fragments not set.}
As stated, your answer looks like this: aStringKey = realAndValidJSONSurroundedByCurvyBrackets, which is not a valid JSON.
After discussion in chat, you have contact with the server side, and it should be their responsibility to give proper JSON. Until they fix it, in order to keep working, you can do:
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
str = [str stringByReplacingCharactersInRange:NSMakeRange(0, [#"aStringKey = " length] ) withString:#""];
NSError *jsonError = nil;
NSDictionary *jsonFinal = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&jsonError];
if (jsonError)
{
NSLog(#"Error: %#", jsonError);
}
But remember, that's a "quick hack/fix" and shouldn't be left in final version and remove as soon as possible.
You tried:
NSError *err = nil;
#try
{
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
}
#catch (NSException *exception)
{
NSLog( #"Exception caught %#",exception);
}
The #try{}#catch(NSException *exception) shouldn't work since +JSONObjectWithData:options:error: shouldn't throw a NSException in your case, so in theory, there is nothing to catch, and but it may still not work (since there is a NSError).
Of course, since data parameter should be non null, if it's nil, you'll get a NSException (which would log Exception caught data parameter is nil), but that's another issue and doesn't assure you that the parsing went wrong (because of invalid JSON like in our case) if there is no exception.
Try this:
NSMutableDictionary *jsonObject;
NSError *err = nil;
#try
{
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
}
#catch (NSException *exception)
{
NSLog( #"Exception caught %#",exception);
}
NSDictionary *info = jsonObject;

Recreate JSON data in Objective-C

I'm trying to build an app on the Feedly API. In order to be able to mark categories as read, I need to post some data to the API. I'm having no success, though.
This is what the API needs as input:
{
"lastReadEntryId": "TSxGHgRh4oAiHxRU9TgPrpYvYVBPjipkmUVSHGYCTY0=_1449255d60a:22c3491:9c6d71ab",
"action": "markAsRead",
"categoryIds": [
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/photography"
],
"type": "categories"
}
And this is my method:
- (void)markCategoryAsRead: (NSString*)feedID{
NSLog(#"Feed ID is: %#", feedID);
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedUrl = [NSURL URLWithString:#"https://sandbox.feedly.com/v3/markers"];
NSError *error = nil;
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"markAsRead", #"action",
#"categories", #"type",
#[feedID], #"categoryIds",
#"1367539068016", #"asOf",
nil];
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
NSLog(#"Postdata is: %#", postdata);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:feedUrl];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request addValue:accessToken forHTTPHeaderField:#"Authorization"];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *errror = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&errror];
NSLog(#"Response code: %ld", (long)[response statusCode]);
if ([response statusCode] >= 200 && [response statusCode] < 300)
{
NSLog(#"It's marked as read.");
} else {
if (error) NSLog(#"Error: %#", errror);
NSLog(#"No success marking this as read. %#", response);
}
}
It keeps throwing a 400 error though, saying bad input. What am I doing wrong?
You're not doing anything with postdata after creating it. Attach it to the request.
[request setHTTPBody:postData];
There are a few problems in your code. Here are some I noticed:
You're not using postData.
The dictionary you make in tmp doesn't look like the dictionary you said you wanted to send. Where's lastReadEntryId, for example?
NSString *feedUrl should be NSURL *feedUrl
Stylistically, you should be using the dictionary literal syntax to create your dictionary. This will make it easier to debug.

NSURL directory files

I have for example : www.example.com/ url.
Inside that URL there are few directories for example www.example.com/dir1/ and inside that there are images when clicked I get www.example.com/dir1/image1.jpg.
My problem is that I need to get all files inside www.example.com/dir1/ , so all images that are inside that directory on web. Based on that names I can get final url (like www.example.com/dir1/image1.jpg) but I need to get all the names of images and dunno how.
Thanks.
If you are seeing the apache directory listing you can parse that html and get all your .jpg files.
http://www.raywenderlich.com/14172/how-to-parse-html-on-ios is a tutorial on how to parse HTML
If this is on your server, you need some mechanism to retrieve the names of the files.
For example, if PHP, this is a script that returns a JSON response of all of the JPG/PNG files:
<?php
header('Content-type: application/json');
$files = scandir('.');
$images = array();
foreach ($files as $file)
{
switch(strtolower(substr(strrchr($file,'.'),1)))
{
case 'png':
case 'jpeg':
case 'jpg': $images[] = $file;
}
}
echo json_encode($images);
?>
You can then use NSURLConnection (or AFNetworking or whatever) to retrieve this and convert the JSON to a NSArray.
For example, using AFNetworking:
NSURL *url = [NSURL URLWithString:#"http://yourwebserver.com/some/path/images.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([responseObject isKindOfClass:[NSArray class]])
[self doSomethingWithImageNames:responseObject];
else
NSLog(#"expected array, received: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"AFHTTPRequestOperation error: %#", error);
}];
[op start];
Or NSURLConnection:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"sendAsynchronousRequest error: %#", connectionError);
return;
}
NSError *jsonError = nil;
NSArray *imageNames = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(#"JSONObjectWithData error: %#", jsonError);
return;
}
[self doSomethingWithImageNames:imageNames];
}];
If you have to rely upon the HTML response, while you generally shouldn't use regular expressions, in this limited use case, you can probably get away with it. In my case, my web server reports links to the files using filename syntax, so I can grab those href tags with something like:
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFHTTPResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (![responseObject isKindOfClass:[NSData class]]) {
NSLog(#"Was expecting `NSData` and got %#", responseObject);
return;
}
NSString *string = [[NSString alloc] initWithData:(NSData *)responseObject encoding:NSUTF8StringEncoding];
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"<a\\s[\\s\\S]*?href\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSMutableArray *results = [NSMutableArray array];
[regex enumerateMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
[results addObject:[string substringWithRange:[result rangeAtIndex:1]]];
}];
[self doSomethingWithImageNames:results];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"AFHTTPRequestOperation error: %#", error);
}];
[op start];

Getting list of "friends" from twitter

I'm trying to get the list of friends from twitter.
I'm trying this code: But i receive a NSDictionary with 5 keys: Next cursor, previous cursors, next cursor str, previous cursor str and users: the key user has 20 objects in value..but all are empty...
Whats wrong?
-(void) obterInformacoesTwitter {
NSURL *url = [NSURL URLWithString:#"https://api.twitter.com/1.1/friends/list.json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:_contaSelecionada.username forKey:#"screen_name"];
NSLog(#"Screen name %#", _contaSelecionada.username);
TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:parameters requestMethod:TWRequestMethodGET];
request.account = _contaSelecionada;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if (responseData) {
NSError *error = nil;
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
NSArray *dictArray = [dict valueForKey:#"users"];
if([dict objectForKey:#"error"]!=nil)
{
}
else
{
}
}
}];
[parameters release];
[request release];
}
Have you tried if the JSON valid? With some online JSON viewers, I get:
JSON data URL inaccessable.

JSON to Objective-C Dictionary

I'm making URL Request to an API but I dont know how to render the JSON, It generates an array of multiple users like this [{"user": "value"}, {"user":"value"}] and I was trying to use a TableView so I need an NSDictionary but i think is better to render a JSON like {users: [{"user": "value"}, {"user":"value"}]}. I have this code to make the request
#import "JSONKit.h"
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
users = [[jsonData objectFromJSONData] objectForKey:#"users"];
usersKeys = [users allKeys];
but I'm getting this error
2012-09-16 18:51:11.360 tableview[2979:c07] -[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180
2012-09-16 18:51:11.362 tableview[2979:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180'
I dont really know how to accomplish this so any help is useful, thanks
You are getting that error because whatever got parsed out of "jsonData" isn't necessarily what you expected (i.e. a dictionary).
Perhaps you need some error checking in that code of yours.
For example:
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(jsonData)
{
id objectReturnedFromJSON = [jsonData objectFromJSONData];
if(objectReturnedFromJSON)
{
if([objectReturnedFromJSON isKindOfClass:[NSDictonary class]])
{
NSDictionary * dictionaryFromJSON = (NSDictionary *)objectReturnedFromJSON;
// assuming you declared "users" & "usersKeys" in your interface,
// or somewhere else in this method
users = [dictionaryFromJSON objectForKey:#"users"];
if(users)
{
usersKeys = [users allKeys];
} else {
NSLog( #"no users in the json data");
}
} else {
NSLog( #"no dictionary from the data returned by the server... check the data to see if it's valid JSON");
}
} else {
NSLog( #"nothing valid returned from the server...");
}
} else {
NSLog( #"no data back from the server");
}
I was thinking on something like this
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
JSONDecoder *decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray *json = [decoder objectWithData:jsonData];
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSDictionary *user in json) {
[objects addObject:[user objectForKey:#"user" ]];
[keys addObject:[user objectForKey:#"value" ]];
}
users = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSLog(#"users: %#", users);
usersKeys = [users allKeys];
But it doesnt look efficient for many items or im wrong?