NSJSONSerialization encoding? - ios

I'm trying to convert my NSDictionary to a json string and then send the data to my web api via HTTPBody (POST request). I convert my dictionary to json like this:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
What I found is that this above method, is not encoding my data (at least special characters like ampersand is not being handled). So the data received on the server side is a mess and I can't read it properly.
For more details on what is happening, assume the following dictionary:
"salutation":"Mrs."
"companyName":"T & F LLP"
"firstName":"Tania"
"country":"Canada"
This dictionary is converted to NSData using the above method and later used like this
[request setHTTPBody:nsDataFromJson];
What do I receive on the server side? I get this
{"contact":"{\"firstName\":\"Tania\",\"salutation\":\"Mrs.\",\"company\":\"Aird
I only get the data up to the special character & and I can only assume that this is happening because the first method I mentioned is not encoding special characters like the &
So I solved this (just for the time being) by converting the dictionary into a json string then replacing each & with %26 then creating NSData from this new string (with the special characters handled). Then I get the full body on my server.
So any idea how to properly handle this?
By the way, the same problem occurs if I use SBJSON too.

It has been 3 months, so I guess the problem must have been solved by now.
The reason the received JSON data is corrupted is because the parser interpreted & (ampersand) as a part of the URL address. Borrowing some codes from this link, I wrote this function to percent-encode & and a few other characters that may get confused:
+ (NSDictionary*) percentEncodeDictionayValues:(NSDictionary*) dict
{
NSMutableDictionary* edict=[NSMutableDictionary dictionaryWithDictionary:dict];
NSMutableCharacterSet* URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[URLQueryPartAllowedCharacterSet removeCharactersInString:#"?&=#+/'"];
for(NSString* key in [dict allKeys])
{
if([dict[key] isKindOfClass:[NSString class]])
edict[key] = [dict[key] stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
}
return edict;
}
So you can preprocess your NSDictionary object with this function before feeding into NSJSONSerialization, and the received data will have & and other characters preserved.

Related

How do I POST raw NSData as well as some NSStrings to my server?

I have a large piece of NSData I want to send to my server, but I also want to send a string dictionary of string keys mapped to string keys.
How do I POST both in the same request?
Almost all guides show wrapping it in an NSDictionary then using NSJSONSerialization to turn it into NSData then POST that, but I can't have NSData and NSStrings in the same NSDictionary it just crashes, so I assume I have to keep it separate, but how would that look?
Essentially how do I serialize JSON into NSData and then also have a separate NSData blob with it?
let body = NSMutableDictionary()
body.setValue("myString" forKey: "stringType")
body.setValue(data?.base64EncodedString(options: .lineLength64Characters) forKey: "dataType")
In this way you can have both data and string in the dictionary.
Here 'data?.base64EncodedString(options: .lineLength64Characters)' returns you a string with base64 encoding. So your dictionary contains only string and at server end you have to covert it back to data.
Hope it solves your issue

Issue in GDataXMLDocument when try [dataUsingEncoding:NSUTF8StringEncoding]?

I am using GDataXMLDocument. I need to parse very simple XML string. When I try to init XML with string I receive error:
-[myObj dataUsingEncoding:]: unrecognized selector sent to instance 0x7afb5690
My string is:
<rootNode>
<detail1>value</detail1>
<detail2>value</detail2>
<detail3>value</detail3>
<detail4>value</detail4>
</rootNode>
The line of the error is:
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
where I need to encode my string no NSData, so I can init my parser with it.
I suppose the problem is in NSUTF8StringEncoding, but I can not understand why!
I am using ARC with NON ARC for GDataXML set in compilation options.
How to solve this?
P.S. I have a remark which might be important. I receive an array from SOAP service. I used sudzc.com tool to create my classes. The SOAP service send to me array of structures. When I receive data using po command see what is inside and I decided that it consists of NSArray with XML sting inside. In general I extract each element of an array and try to parse it as XML to extract data I need.
May be I am wrong and that is the reason for that error.
I don't know why but I fix it casting once again to NSString with format using:
NSString *properStr = [NSString stringWithFormat:#"%#", str];
I am not sure why I need this, but it is wotking now.

iOS RestKit 0.2 What is the best way to parse local Json

I wave read many articles about parsing a json via an Http request but almost none answers the question about what is the most straight forward way to parse o local json string. I found some deferent solutions here Deserializing local NSString of JSON into objects via RestKit (no network download) some of them work some others don't. Is there any "official" RestKit support for local JSON string deserialization?
Fortunately Apple provides "NSJSONSerialization" class from iOS 5.0. to serialise your data.
Step 1 : convert your local JSON string to "NSData"
NSString *strLocalJSON = #"{data= "some data"}"; //just for ex. may not be valid one
NSData *dataJSON = [str dataUsingEncoding:NSUTF8StringEncoding];
Step2:
id jsonobject= [NSJSONSerialization JSONObjectWithData:dataJSON options:NSJSONReadingMutableContainers error:nil]; // resulting object may contain Dictionary or Array depends on your localjson
for further info refer https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html
If your JSON is in a file then you use a file:// NSURL when you create your RestKit object manager. Everything else works as normal.
If the JSON is already in code, then you should save it to a file, or why are you needing to do any mapping? Anyway, you could use a combination of NSJSONSerialization and RKMappingOperation.

Determining Issue With Retrieving JSON from URL in iPhone

Let me start off by saying that I am not particularly trying to find a solution, just the root cause of the problem. I am trying to retrieve a JSON from a url. In browser, the url call works just fine and I am able to see the entire JSON without issue. However, in x-code when simply using NSURLConnection, I am getting data bytes, but my NSString is null.
theString = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
After doing some research I have found that I am probably trying to use the wrong encoding. I am not sure what type of encoding is being used by the url, so on first instinct I just tried some random encoding types.
NSString* myString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSString* myString2 = [[NSString alloc] initWithData:data encoding:NSUTF16StringEncoding];
NSString* myString3 = [[NSString alloc] initWithData:data encoding:NSWindowsCP1252StringEncoding];
NSASCIIStringEncoding and NSWindowsCP1252StringEncoding is able to bring back a partially correct JSON. It is not the entire JSON thatI am able to view in the browser, and some characters are a little messed up, but it is something. To try and better determine what encoding was used, I decided to use the following method to try and determine it by looking at what encoding returned.
NSError *error = nil;
NSStringEncoding encoding;
NSString *my_string = [[NSString alloc] initWithContentsOfURL:url
usedEncoding:&encoding
error:&error];
My NSStringEncoding value is 3221214344. And this number is consistent everytime I run the app. I can not find any NSStringEncoding values that even come close to matching this.
My final question is: Is the encoding used for this url not consumable by iOS, is it possible that multiple types of encoding was used for this url, or is there something else that I could be doing wrong on my end?
It's best not to rely on Cocoa to figure out the string encoding if possible, especially if the data might be corrupted. A better approach would be to check if the value indicated by the HTTP Content-Type header specifies a character set like in this example:
Content-Type: text/html; charset=ISO-8859-4
Once you're able to parse and retrieve a character set name from the Content-Type header, you need to convert it to an NSStringEncoding, first by passing it to CFStringConvertIANACharSetNameToEncoding, and then passing the returned CF string encoding to CFStringConvertEncodingToNSStringEncoding. After that, you can initialize your string using -[NSString initWithData:encoding:].
NSData *HTTPResponseBody = …; // Get the HTTP response body
NSString *charSetName = …; // Get a charset name from the Content-Type HTTP header
// Get the Core Foundation string encoding
CFStringEncoding cfencoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)charSetName);
// Confirm this is a known encoding
if (cfencoding != kCFStringEncodingInvalidId) {
// Initialize the string
NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
NSString *JSON = [[NSString alloc] initWithData: HTTPResponseBody
encoding: nsencoding];
}
You still may run into problems if the string data you're working with is corrupted. For example, in the above code snippet, perhaps charSetName is UTF-8, but HTTPResponseBody can't be parsed as UTF-8 because there's an invalid byte sequence. In this situation, Cocoa will return nil when you try to instantiate your string, and short of sanitizing the data so that it conforms to the reported string encoding (perhaps by stripping out invalid byte sequences), you may want to report an error back to the end user.
As a last-ditch effort — rather than reporting an error — you could initialize a string using an encoding that can handle anything you throw at it, such as NSMacOSRomanStringEncoding. The one caveat here is that unicode / corrupted data may show up intermittently as symbols or unexpected alphanumerics.
Even though it seems that the answer has been provided in the comments (using iso-8859-1 as the correct encoding) I thought it worthwhile to discuss how I would go about debugging this problem.
You said that the Desktop Browser (Chrome) can digest the data correctly, so let's use that:
Enable Developer Tools https://developers.google.com/chrome-developer-tools/
When the Dev Tools window is open, switch to "network" and execute your call in that browser tab
check the output by clicking on the request url - it should give you some clue.
If that doesn't work, tools like Postman can help you to recreate the call before you implement it on the device

IOS cannot decode emoji unicode in json format correctly, and Emoji icons are displayed as squares

I am working on an iPhone app which allows people to send messages with Emoji icons. I saved the icon in Mysql with charset utf8mb4 and collation utf8mb4_unicode_ci, and all the emoji icons is saved correctly in my database. However, when I return json back to the client (php json_encode), the Emoji is encoded as something like this: '\ud83d\ude04', and iPhone displays it as a square. However, if I return as XML, the Emoji Icon won't become unicode like this: '\ud83d\ude04', it will just be the icon.
I am wondering if this is an issue on my server, or on my client. If it is my client, how can object c decode it correctly.
Can someone please help?
Thanks
"\ud83d\ude04" is the JSON Unicode escape sequence for U+D83D U+DE04, which is the "surrogate pair" for the Unicode U+1F604 (SMILING FACE WITH OPEN MOUTH AND SMILING EYES).
But NSJSONSerialization decodes this correctly, as can be seen in the following example:
const char *jsonString = "{ \"emoji\": \"\\ud83d\\ude04\" }";
NSLog(#"JSON: %s", jsonString);
NSData *jsonData = [NSData dataWithBytes:jsonString length:strlen(jsonString)];
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
self.myLabel.text = [jsonDict objectForKey:#"emoji"];
NSLog(#"Emoji: %#", self.myLabel.text);
Output:
JSON: { "emoji": "\ud83d\ude04" }
Emoji: 😄
and the Emoji symbol is also displayed correctly (tested with iPhone device and Simulator).
Please follow following steps:
Convert Emoji characters to base64 and send to server using Json.
On server side save base64 in database without decode.
When you want to display Emoji on Application then retrieve same base64 data from server.
Decode retrieve string and display on app.
Your Emoji character will display properly.
Note: When you want to Show on webPage then Decode data when you display data on WebPage.
Our team fixed this problem by transfer utf data to server, saving them in mysql utf8mb4 codepage and receiving with base64. Server convert saved data to base64 on demand.

Resources