NSJSONSerialization creates garbage - ios

I have some problems with creating a NSString-representation (JSON-string) of a NSDictionary using NSJSONSerialization. I have used JSONKit before, but since its kind of deprecated in iOS9 (and crashes), I switched to NSJSONSerialization.
This is my code:
// `userSettings` will be of type NSMutableDictionary*
NSData* data= [NSJSONSerialization dataWithJSONObject:userSettings options:0 error:&error];
NSString* settingsString= [NSString stringWithUTF8String:data.bytes];
currentUser.settings= settingsString; // NSString* property
Now, from time to time, this code works, but then sometimes the settingsString will be nil. And when I inspect the data object in the debugger, the bytes property shows the JSON-String followed by some random garbage, like this:
1 = 0x00007ff1ba814000 "{\"residua
...
lculatePlanned\":\"0\",\"wizardUserId\":\"\"}UITextColor\x91UISystemColorName\x94UIBaselineAdjustment\x8cUISystemFont\x89NS.intval\x8eUIShadowOffset\x94UIAutoresizeSubviews\x8dUIContentMode\x85NSRGB\x8aUIFontName\x8bUITextLabel\x8eNSInlinedValue\x91UIDetailTextLabel\x99UIUserInteractionDisabled\x9dUITableCellBackgroundColorSet\x94UINibEncoderEmptyKey\x87NSWhite\x8cNSColorSpace\x8fUITextAlignment\xa3UINibAccessibilityConfigurationsKey\x92UIAutoresizingMask\x99UIProxiedObjectIdentifier\x87UIAlpha\x87UIWhite\x9aUIFontDescriptorAttributes\x8cUIFontTraits\x86NSSize\x95UIColorComponentCount\x91UIMinimumFontSize\x86UIText\x96UIMultipleTouchEnabled\x8dUIDestination\x94UIMi..."
^ start of garbage after end of dictionary
What am I doing wrong?

Do not use + stringWithUTF8String:, it relies on a A NULL-terminated C array of bytes and there is only a NULL terminator by chance and it may be well after the end of the charactery you expect.
Instead use:
- (instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
Ex:
NSString *settingsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Related

When the data and encoding are known to be valid, what other reason could cause NSString initWithData to return nil?

In the reference for [NSString initWithData:encoding:] it says,-
"Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding)"
I know the data and encoding are correct, because the data was returned by NSJSONSerialization dataWithJSONObject, so it must be valid and it must be UTF8
My question is:
What other reason could cause NSString initWithData to return nil?
I have researched this extensively and only found answers that suggest the data and/or encoding may be invalid, but I have checked and these are definitely correct.
My code is very similar to the following:
NSData* data = [NSJSONSerialization dataWithJSONObject:array
options:0
error:nil];
if (!data) return nil;
NSString* string = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
array must be valid because data is not nil
data must be valid & UTF8 because it was returned by NSJSONSerialization dataWithJSONObject
I cannot post my data because it is proprietary which should not matter for the reasons given
What other reason could cause NSString initWithData to return nil?

Parsing JSON object for iOS application

Currently, I have within my iPhone app a URL with which contains a JSON object that I must parse.
I am able to fetch the JSON object, convert the object to an NSString, now the issue is parsing the object/NSString object.
I am currently using SBJSON.
How do I go about iterating through the key elements of the JSON object using SBJSON's framework?
{
"status":"SUCCESS",
"fields":[
{
"type":"instant",
"field":"GenerationPower",
"label":"now",
The JSON object is MUCH larger than just these keys and key elements but once this issue is resolved, I'm sure the rest of the JSON object will be easy since i'll have a reference.
Thank you Stackoverflow!
EDIT:
Here's some code to clarify my issue.
+ (NSString *) pullingInfo
{
NSURL *solarWebURL = [NSURL URLWithString:myurl];
if (solarWebURL)
{
NSLog(#"Calling: %#", solarWebURL);
NSData *jsonData = [NSData dataWithContentsOfURL:solarWebURL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return jsonString;
}
NSString* errorMessage = #"Error reading URL";
return errorMessage;
}
+ (NSDictionary *) jsonDictionaryObject
{
NSDictionary * jsonDictionary = [[NSDictionary alloc] init];
NSString * monroeString = [MonroeParser pullingInfo];
return jsonDictionary;
}
So as I said before, I have already loaded the JSON object into an NSString object "jsonString". Now I would like to start parsing the string.
I figure I may not even need to use JSON's framework for parsing, I can probably just parse the NSString using NSString conventions provided by Apple.
Any idea's? But maybe this isn't efficient....
Sine you are using SBJSON, why are you even converting the NSData to an NSString? You can use -objectWithData method for SBJSONParser to directly read the NSData into an NSDictionary.
http://sbjson.org/api/3.2/Classes/SBJsonParser.html#//api/name/objectWithData:
Let pullingInfo return an id. And in you calling function check if the id is of type NSDictionary or NSArray and parse accordingly.

NSJSONSerialization sometimes returns null in async request

I've been developing app, that makes asynchronous requests for JSON type of data. Lately, I found strange bug in my code and I can't tell why it is happening.
Ok to the code!
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSError *error=nil;
result = [NSJSONSerialization JSONObjectWithData:retrievedData options:kNilOptions error:&error];
NSLog(#"Result %#",result);
NSLog(#"Retrieved data %#",retrievedData);
}
Result is NSDictionary, retrievedData is NSMutableData.
99% of the time, it works fine, connectionDidFinishLoading gets called, and my result is populated. However, in that 1% of the time retrieved data is filled with data, but my result is null.(as you can see on the picture. Could anyone help me please?
Edit: I get following error
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Garbage at end.) UserInfo=0x753e5c0 {NSDebugDescription=Garbage at end.}
It would help if you take a look at the error first, to see if that gives any indication of what is wrong.
[edit]
Your error mentions the reason: Garbage at end..
The response from the webserver is not valid JSON, it contains invalid characters at the end of the output.
I had the same issue. First, look what is a data that wasn't parsed correctly - in my case I did
NSString *str = [[NSString alloc] initWithData:retrievedData encoding:NSUTF8StringEncoding];
In my case the reason was - if server sent a few socket.write()'s in a row - all data was received in one single chunk, like
{first:json}{second:json}..
of course this cannot be parsed as one single json, so I have to introduce delimiter, and split the received buffer into correct chunks.
This is a little late but nothing online worked for me until I did this:
NSString * dataInString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [dataInString rangeOfString:#"}" options:NSBackwardsSearch];
if(range.location != NSNotFound)
dataInString = [dataInString substringWithRange:NSMakeRange(0,range.location+1)];
Always worked since then.
I had the same error, the problem was my server was attaching some extra lines to my json response, that would not appear when i will get the response in my browser. Using curl from terminal you can see the actual output.
The hack was to truncate the extra characters. with json either you have an array or dictionary. Depending on your json structure, you can use the code (as above answer) but look for the comment in line 2
NSString * str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [str rangeOfString:#"}" options:NSBackwardsSearch]; // } for dictionary, ] for array
if(range.location != NSNotFound)
str = [str substringWithRange:NSMakeRange(0,range.location+1)];
once you get your string clean from garbage data, you can convert it to data again.
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
and now from this data you can get your array or dictionary.
id jsonObject = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions error:&error]; // i used id to be general, you can use array or dictionary structure or later cast this object to as per json

NSJSONSerialization and SBJson work oddly

I've tried converting the same NSDictionary object into NSData and then NSString using NSJSONSerialization and SBJsonWriter several times, and sometimes got a different string. even null. It's quite weird and I can't find any reason. =( JSONKit and YAJL don't have problems like this.
Following is my test code.
for (int i = 0; i < 5; i++) {
NSDictionary *d = [NSDictionary dictionaryWithObject:#"value" forKey:#"key"];
NSData *data = [NSJSONSerialization dataWithJSONObject:d options:0 error:nil];
NSLog(#"%#", [NSString stringWithUTF8String:data.bytes]);
}
and the console output is ...
2012-04-25 01:35:33.113 Test[19347:c07] {"key":"value"}
2012-04-25 01:35:33.114 Test[19347:c07] (null)
2012-04-25 01:35:33.114 Test[19347:c07] {"key":"value"}
2012-04-25 01:35:33.114 Test[19347:c07] {"key":"value"}
2012-04-25 01:35:33.115 Test[19347:c07] (null)
output changes every time I run the test code.
data's byte size is the same, but UTF8-converted string length varies.
The bytes in an NSData object do not necessarily comprise a NUL-terminated string. If you want to convert the data into an NSString, do this instead:
[[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSUTF8StringEncoding]
There's a possibility that some parsers write '\0' to the end of the data they return for safety, which explains why they behave more predictably. But you shouldn't rely on that behavior, as you've seen.

iOS : decode utf8 string

I'm receiving a json data from server with some strings inside. I use SBJson https://github.com/stig/json-framework to get them.
However when I output some strings at UILabel they look like this: \u0418\u043b\u044c\u044f\u0411\u043b\u043e\u0445 (that's Cyrillic symbols)
And it's all right with latin characters
How can I decode it into normal symbols?
Some code about getting data:
NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *stringData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *object = [parser objectWithString:stringData error:nil];
NSString *comments = [NSString stringWithFormat:#"%#",[object valueForKey:#"comments"]];
String comments has a very special format, so I'm doing some operation like stringByTrimmingCharactersInSet ,
stringByReplacingOccurrencesOfString ,
NSArray* json_fields = [comments_modified componentsSeparatedByString: #";"];
to get a final data.
This is an example of received data after some trimming/replacing (it's NSString* comments):
"already_wow"=0;"date_created"="2012/03/1411:11:18";id=41598;name="\U0418\U043b\U044c\U044f\U0411\U043b\U043e\U0445";text="\U0438\U043d\U0442\U0435\U0440\U0435\U0441\U043d\U043e";"user_id"=1107;"user_image"="user_image/a6/6f/96/21/20111220234109510840_1107.jpg";"user_is_deleted"=0;username=IlyaBlokh;"wow_count"=0;
You see that fields text and name are encoded
If I display them on the view (at UILabel for example), they still look the same
maybe the string returned is just the unicode string representation (ascii string), that's means not returned the content encoded with utf8, to try this with NSASCIIStringEncoding to get stringData

Resources