Strange NSData Output - objective-c

I have some unexpected results coming from the following code:
- (NSData *)postDataWithDict:(NSDictionary *)postDict
{
// Assume key is urlValid
NSUInteger postCount = [postDict count];
NSMutableArray *buildArray = [[NSMutableArray alloc] initWithCapacity:postCount];
for (NSString *key in postDict) {
//post data is key=value&key=value&key=value...
// start with key
NSMutableString *arrayLine = [NSMutableString stringWithString:key];
[arrayLine appendString:#"="];
// analyze and then append value
id postValue = [postDict objectForKey:key];
if ([postValue isKindOfClass:[NSNumber class]]) {
NSString *valueString = [NSString stringWithFormat:#"%#",postValue];
[arrayLine appendString:valueString];
}
else if ([postValue isKindOfClass:[NSString class]]) {
NSString *urlEncodedString = [self urlEncodeValue:postValue];
[arrayLine appendString:urlEncodedString];
}
else {
NSLog(#"postKey: %#, postValue class:%#", key, [postValue class]);
NSError *jsonError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postValue
options:0
error:&jsonError];
if (jsonError != nil) {
NSLog(#"JSON serialization failed: %# - %#", [jsonError localizedDescription], [jsonError userInfo]);
NSLog(#"value: %#", postValue);
}
else {
// need to urlencode
NSString *stringifyJSON = [NSString stringWithUTF8String:[jsonData bytes]];
NSString *urlJSONstring = [self urlEncodeValue:stringifyJSON];
[arrayLine appendString:urlJSONstring];
}
}
[buildArray addObject:arrayLine];
}
NSString *postString = [buildArray componentsJoinedByString:#"&"];
NSData *postData = [postString dataUsingEncoding:NSUTF8StringEncoding];
//testing
NSLog(#"Post Dict: %#", postDict);
NSLog(#"Post Array: %#", buildArray);
NSLog(#"Post String: %#", postString);
NSLog(#"Post Data: %#", [NSString stringWithUTF8String:[postData bytes]]);
return postData;
}
My //testing log results:
Post Dict: {
authenticationString = b3210c0bc6d2c47f4c2f7eeea12e063d;
dataMode = updateSingle;
dateCreated = "374300293.81108";
dateModified = "374609294.313093";
dateSynced = "374610683.588062";
entityName = CommodityTypes;
myName = 21;
sortKey = 21;
username = iPhoneAdamek;
usernameString = iPhoneAdamek;
uuidKey = "53403EAE-DD4F-4226-A979-316EF7F43991";
}
Post Dict looks good. Just what I wanted.
2012-11-14 13:31:23.640 FoodyU[11393:907] Post Array: (
"myName=21",
"dataMode=updateSingle",
"dateSynced=374610683.588062",
"uuidKey=53403EAE-DD4F-4226-A979-316EF7F43991",
"sortKey=21",
"dateModified=374609294.313093",
"entityName=CommodityTypes",
"dateCreated=374300293.81108",
"authenticationString=b3210c0bc6d2c47f4c2f7eeea12e063d",
"usernameString=iPhoneAdamek",
"username=iPhoneAdamek"
)
Post Array looks good. Strings are all set to be concatenated for a HTTP POST string.
2012-11-14 13:31:23.641 FoodyU[11393:907] Post String: myName=21&dataMode=updateSingle&dateSynced=374610683.588062&uuidKey=53403EAE-DD4F-4226-A979-316EF7F43991&sortKey=21&dateModified=374609294.313093&entityName=CommodityTypes&dateCreated=374300293.81108&authenticationString=b3210c0bc6d2c47f4c2f7eeea12e063d&usernameString=iPhoneAdamek&username=iPhoneAdamek
Post String looks good. I'm ready to convert it to data to use in [NSMutableURLRequest setHTTPBody:postData].
2012-11-14 13:31:23.643 FoodyU[11393:907] Post Data: myName=21&dataMode=updateSingle&dateSynced=374610683.588062&uuidKey=53403EAE-DD4F-4226-A979-316EF7F43991&sortKey=21&dateModified=374609294.313093&entityName=CommodityTypes&dateCreated=374300293.81108&authenticationString=b3210c0bc6d2c47f4c2f7eeea12e063d&usernameString=iPhoneAdamek&username=iPhoneAdamekoneAdamek;
usernameString = iPhoneAdamek;
uuidKey = "53403EAE-DD4F-4226-A
WTF??? How did &username=iPhoneAdamek become &username=iPhoneAdamekoneAdamek;
usernameString = iPhoneAdamek;
uuidKey = "53403EAE-DD4F-4226-A?
I'm fairly new to Cocoa. Is there something wrong with:
NSData *postData = [postString dataUsingEncoding:NSUTF8StringEncoding];
or
NSLog(#"Post Data: %#", [NSString stringWithUTF8String:[postData bytes]]);

You shouldn't be using NSLog of NSData as,
NSLog(#"Post Data: %#", [NSString stringWithUTF8String:[postData bytes]]);
Instead use it as,
NSLog(#"Post Data: %#", [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding]);
[NSString stringWithUTF8String:[postData bytes]] always returns unexpected results.
As per documentation for bytes,
bytes: Returns a pointer to the receiver’s contents.
And as per Apple documentation for stringWithUTF8String,
stringWithUTF8String:
Returns a string created by copying the data from a given C array of UTF8-encoded bytes.
Parameters: bytes - A NULL-terminated C array of bytes in UTF8 encoding.
So when you are using [postData bytes], it is not NULL-terminated and hence when you are using with stringWithUTF8String returns the data written in memory till it encounters a NULL-termination.

Related

SIGABRT when trying to parse JSON

I am trying to parse a JSON string but it falls with a SIGABRT error.
Code I am using:
NSString *test = #'{"notifications":[{"id":"fae9a890-2791-46e2-ad9c-5a72f602a2e8","created":"2017-06-17T21:57:28+00:00","thread_id":3964,"reply_id":null,"thread":{"id":3964,"subject":"[CakePHP] Pagination"},"users_from":{"username":"Royal"},"content":"has posted a reply in"},{"id":"00732627-f23e-423e-b885-add968575972","created":"2017-06-17T20:08:05+00:00","thread_id":3964,"reply_id":79478,"thread":{"id":3964,"subject":"[CakePHP] Pagination"},"users_from":{"username":"Royal"},"content":"has quoted you in"}]}';
NSError *error;
NSMutableDictionary *allCourses = [NSJSONSerialization JSONObjectWithData:test
options:kNilOptions
error:&error];
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
else {
NSArray *monday = allCourses[#"notifications"];
for ( NSDictionary *theCourse in monday )
{
NSLog(#"----");
NSLog(#"Title: %#", theCourse[#"subject"] );
NSLog(#"Id: %#", theCourse[#"id"] );
NSLog(#"----");
}
}
Thanks.
The mistake is in your NSString declaration:
NSString *test = #'{"notifications"}';
This is wrong.
NSString must always use this format: #"bla bla bla".
You need to incorporate escapes for double quotes in your test string like this
NSString *test = #"{\"notifications\"}";

how to convert an array into string? [duplicate]

In my iPhone aplication I have a list of custom objects. I need to create a json string from them. How I can implement this with SBJSON or iPhone sdk?
NSArray* eventsForUpload = [app.dataService.coreDataHelper fetchInstancesOf:#"Event" where:#"isForUpload" is:[NSNumber numberWithBool:YES]];
SBJsonWriter *writer = [[SBJsonWriter alloc] init];
NSString *actionLinksStr = [writer stringWithObject:eventsForUpload];
and i get empty result.
This process is really simple now, you don't have to use external libraries,
Do it this way, (iOS 5 & above)
NSArray *myArray;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myArray options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
I love my categories so I do this kind of thing as follows
#implementation NSArray (Extensions)
- (NSString*)json
{
NSString* json = nil;
NSError* error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error];
json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return (error ? nil : json);
}
#end
Although the highest voted answer is valid for an array of dictionaries or other serializable objects, it's not valid for custom objects.
Here is the thing, you'll need to loop through your array and get the dictionary representation of each object and add it to a new array to be serialized.
NSString *offersJSONString = #"";
if(offers)
{
NSMutableArray *offersJSONArray = [NSMutableArray array];
for (Offer *offer in offers)
{
[offersJSONArray addObject:[offer dictionaryRepresentation]];
}
NSData *offersJSONData = [NSJSONSerialization dataWithJSONObject:offersJSONArray options:NSJSONWritingPrettyPrinted error:&error];
offersJSONString = [[NSString alloc] initWithData:offersJSONData encoding:NSUTF8StringEncoding] ;
}
As for the dictionaryRepresentation method in the Offer class:
- (NSDictionary *)dictionaryRepresentation
{
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
[mutableDict setValue:self.title forKey:#"title"];
return [NSDictionary dictionaryWithDictionary:mutableDict];
}
Try like this Swift 2.3
let consArray = [1,2,3,4,5,6]
var jsonString : String = ""
do
{
if let postData : NSData = try NSJSONSerialization.dataWithJSONObject(consArray, options: NSJSONWritingOptions.PrettyPrinted)
{
jsonString = NSString(data: postData, encoding: NSUTF8StringEncoding)! as String
}
}
catch
{
print(error)
}
Try like this,
- (NSString *)JSONRepresentation {
SBJsonWriter *jsonWriter = [SBJsonWriter new];
NSString *json = [jsonWriter stringWithObject:self];
if (!json)
[jsonWriter release];
return json;
}
then call this like,
NSString *jsonString = [array JSONRepresentation];
Hope it will helps you...
I'm a bit late to this party, but you can serialise an array of custom objects by implementing the -proxyForJson method in your custom objects. (Or in a category on your custom objects.)
For an example.

Manipulating Facebook/JSON data

I'm trying to handle Facebook JSON data and transform it into a NSMutable Dictionary, but I'm getting (null) when I try to print the data. Although when I try to do a count, I get a number.
User_likes is NSMutableDictionary which is globally defined. I'm getting (null) on this line:
NSLog(#"User likes: %#", user_likes);
This is my code:
NSString *query =
#"SELECT page_id, type FROM page_fan WHERE uid = me() ";
// Set up the query parameter
NSDictionary *queryParam = #{ #"q": query };
// Make the API request that uses FQL
[FBRequestConnection startWithGraphPath:#"/fql"
parameters:queryParam
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection,
id results,
NSError *error) {
if (error) {
NSLog(#"Error: %#", [error localizedDescription]);
} else {
user_likes = [NSJSONSerialization JSONObjectWithData:results options:kNilOptions error:&error];
NSLog(#"User likes: %#", user_likes);
NSInteger* n_user_likes = [results count];
NSInteger* n_user_likes2 = [user_likes count];
NSLog(#"n user likes %qi", n_user_likes);
NSLog(#"n user likes2 %qi", n_user_likes2);
id val = nil;
id values = [[user_likes allKeys] objectAtIndex:0 ];
NSLog(#"values id %#", values);
When I print results, I get a lot of data from Facebook, this is a sample of it:
data = (
{
"page_id" = 253370381511811;
type = "PUBLIC FIGURE";
},
{
"page_id" = 148389618201;
type = "LOCAL BUSINESS";
},
{
"page_id" = 213631462169238;
type = COMMUNITY;
},
{
"page_id" = 162297750451425;
type = "NON-PROFIT ORGANIZATION";
},
{
"page_id" = 503620106320217;
type = "MEDIA/NEWS/PUBLISHING";
},
you can't do directly
user_likes = [NSJSONSerialization JSONObjectWithData:results options:kNilOptions error:&error];
you need first create a dictionary with the data in results like this:
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:results];
user_likes = [NSString stringWithFormat:#"%d",[[dictionary objectForKey:#"value_of_the_likes"] intValue]];
NSLog(#"%#",user_likes);
NSLog(#"%#",dictionary);
EDIT:
Please, create this class to your project and import in the class where you need use this.
#import <Foundation/Foundation.h>
#interface NSDictionary (JSONExtensions)
+(NSDictionary*)dictionaryWithJSONData:(NSData*)data;
-(NSData*)JSONValue;
-(NSString*)JSONString;
#end
#implementation NSDictionary(JSONExtensions)
+(NSDictionary*)dictionaryWithJSONData:(NSData*)data{
NSError *error = nil;
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if(error){
NSLog(#"%#",error);
return nil;
};
return result;
}
-(NSData*)JSONValue{
NSError *error = nil;
NSData *result = [NSJSONSerialization dataWithJSONObject:self options:kNilOptions error:&error];
if(error){
NSLog(#"%#",error);
return nil;
};
return result;
}
-(NSString*)JSONString{
return [[NSString alloc] initWithData:self.JSONValue encoding:NSUTF8StringEncoding];
}
#end
Hope it can help you.
maybe you forget set up options:
NSJSONReadingOptions options = NSJSONReadingAllowFragments | NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves;
user_likes = [NSJSONSerialization JSONObjectWithData:results options:options error:&error];
i hope this be useful for you!
UPDATE:
Check this :
NSJsonSerialzation not parsing results from Facebook - Cocoa error 3840
Let me know if that helps you!

JSON and 2D array

The following is encoded JSON data from a PHP webpage.
{
{
"news_date" = "2011-11-09";
"news_id" = 5;
"news_imageName" = "newsImage_111110_7633.jpg";
"news_thread" = "test1";
"news_title" = "test1 Title";
},
{
"news_date" = "2011-11-10";
"news_id" = 12;
"news_imageName" = "newsImage_111110_2060.jpg";
"news_thread" = "thread2";
"news_title" = "title2";
},
// and so on...
}
I'd like to grab one buch of info (date/id/image/thread/title), and store it as an instance of a class. However, I have no clue on how to access each object in 2D arrays.
The following is the code I've written to test if I can access them, but it doesn't work.
What would be the problem?
NSURL *jsonURL = [NSURL URLWithString:#"http://www.sangminkim.com/UBCKISS/category/news/jsonNews.php"];
NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL];
SBJsonParser *parser = [[SBJsonParser alloc] init];
contentArray = [parser objectWithString:jsonData];
NSLog(#"array: %#", [[contentArray objectAtIndex:0] objectAtIndex:0]); // CRASH!!
In JSON terminology, that’s not a two-dimensional array: it’s an array whose elements are objects. In Cocoa terminology, it’s an array whose elements are dictionaries.
You can read them like this:
NSArray *newsArray = [parser objectWithString:jsonData];
for (NSDictionary *newsItem in newsArray) {
NSString *newsDate = [newsItem objectForKey:#"news_date"];
NSUInteger newsId = [[newsItem objectForKey:#"news_id"] integerValue];
NSString *newsImageName = [newsItem objectForKey:#"news_imageName"];
NSString *newsThread = [newsItem objectForKey:#"news_thread"];
NSString *newsTitle = [newsItem objectForKey:#"news_title"];
// Do something with the data above
}
You gave me a chance to checkout iOS 5 Native JSON parser, so no external libraries needed, try this :
-(void)testJson
{
NSURL *jsonURL = [NSURL URLWithString:#"http://www.sangminkim.com/UBCKISS/category/news/jsonNews.php"];
NSData *jsonData = [NSData dataWithContentsOfURL:jsonURL];
NSError* error;
NSArray* json = [NSJSONSerialization
JSONObjectWithData:jsonData //1
options:kNilOptions
error:&error];
NSLog(#"First Dictionary: %#", [json objectAtIndex:0]);
//Log output:
// First Dictionary: {
// "news_date" = "2011-11-09";
// "news_id" = 5;
// "news_imageName" = "newsImage_111110_7633.jpg";
// "news_thread" = " \Uc774\Uc81c \Uc571 \Uac1c\Ubc1c \Uc2dc\Uc791\Ud574\Ub3c4 \Ub420\Uac70 \Uac19\Uc740\Ub370? ";
// "news_title" = "\Ub418\Ub294\Uac70 \Uac19\Uc9c0?";
// }
//Each item parsed is an NSDictionary
NSDictionary* item1 = [json objectAtIndex:0];
NSLog(#"Item1.news_date= %#", [item1 objectForKey:#"news_date"]);
//Log output: Item1.news_date= 2011-11-09
}

How to do different actions depending on ASIHTTPRequest?

I'm using ASIFormDataRequest for uploading an image to TwitPic and I get an response, from here all ok. But on - (void)requestFinished:(ASIHTTPRequest *)request I already have an action for a TwitLonger response (which works correctly). Now how would I do a different action depending of the type of response? I tried setting an string and comparing with if, getting the last thing of the response, but with no luck. This is the way I tried:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
NSString *first = [responseString substringFromIndex: [responseString length] - 7];
NSLog(#"%#", first);
if (first == #"</rsp>"+
) {
NSString *responseString = [request responseString];
NSLog(#"%#", responseString);
NSString *result = nil;
// Determine "<div>" location
NSRange divRange = [responseString rangeOfString:#"<mediaurl>" options:NSCaseInsensitiveSearch];
if (divRange.location != NSNotFound)
{
// Determine "</div>" location according to "<div>" location
NSRange endDivRange;
endDivRange.location = divRange.length + divRange.location;
endDivRange.length = [responseString length] - endDivRange.location;
endDivRange = [responseString rangeOfString:#"</mediaurl>" options:NSCaseInsensitiveSearch range:endDivRange];
if (endDivRange.location != NSNotFound)
{
// Tags found: retrieve string between them
divRange.location += divRange.length;
divRange.length = endDivRange.location - divRange.location;
result = [responseString substringWithRange:divRange];
}
tweet.text = result;
NSLog(#"%#", result);
}
} else {
// Use when fetching text data
NSString *responseString = [request responseString];
NSLog(#"%#", responseString);
NSString *result = nil;
// Determine "<div>" location
NSRange divRange = [responseString rangeOfString:#"<content>" options:NSCaseInsensitiveSearch];
if (divRange.location != NSNotFound)
{
// Determine "</div>" location according to "<div>" location
NSRange endDivRange;
endDivRange.location = divRange.length + divRange.location;
endDivRange.length = [responseString length] - endDivRange.location;
endDivRange = [responseString rangeOfString:#"</content>" options:NSCaseInsensitiveSearch range:endDivRange];
if (endDivRange.location != NSNotFound)
{
// Tags found: retrieve string between them
divRange.location += divRange.length;
divRange.length = endDivRange.location - divRange.location;
result = [responseString substringWithRange:divRange];
}
tweet.text = result;
[_engine setAccessToken:token];
[_engine sendUpdate:tweet.text];
[self.parentViewController dismissModalViewControllerAnimated:true];
}
}
}
And this is an example of the response:
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
<mediaid>50ia96</mediaid>
<mediaurl>URL GOES HERE</mediaurl>
</rsp>
So ending up, what I want is getting the URL between tags.
Thanks in advance!
Go to their documentation, and scroll down to the "Handling success and failure for multiple requests in delegate methods" section. They give you three alternatives - most of the times it's enough to set the userInfo dictionary when you make the request, and then just read it in your callbacks and take proper action. Some quick code:
set this when you create and start the request:
request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys: #"firstRequestId", #"id", nil];
and then in your callbacks:
if([[request.userInfo objectForKey:#"id"] isEqualToString:#"firstRequestId"]) {
// Handle the request with id 'firstRequestId'
}