NSJSONSerialization and Emoji - ios

I'm currently trying to POST some JSON containing emojis to a python API. I tried feeding the NSJSONSerialization directly with the string containing the emojis from my UITextField but the serializer crashed with no meaningful explanation.
Afterwards I tried to do some format conversion and ended up with something like this:
NSString *uniText = mytextField.text;
NSData *msgData = [uniText dataUsingEncoding:NSNonLossyASCIIStringEncoding];
NSString *goodMsg = [[NSString alloc] initWithData:msgData encoding:NSUTF8StringEncoding] ;
This basically works except that the resulting UTF-8 is kinda double-"escaped" resulting in the following:
"title":"\\ud83d\\udc8f\\ud83d\\udc8f\\ud83d\\udc8f\\ud83d"
Any suggestions how to fix that?

There are two difficulties:
1. Apple hosed NSString WRT UTF Planes 1 and above, the underlying use
of UTF-16 shows through. An example is that length will return 2 for
one emoji character.
2. Whoever decided to put emoji in Plane 1 was
just being difficult, it is the first use of Plane 1 and a lot of
legacy UTF code does not handle that correctly.
Example code (adapted from #Hot Licks):
Updated with OP emoji
NSString *uniText = #"💦💏👒👒💦";
NSDictionary* jsonDict = #{#"title":uniText};
NSData * utf32Data = [uniText dataUsingEncoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"utf32Data: %#", utf32Data);
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:0 error:&error];
if (jsonData == nil) {
NSLog(#"JSON serialization error: %#", error);
}
else {
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"The JSON result is %#", jsonString);
NSLog(#"jsonData: %#", jsonData);
}
NSLog output
utf32Data: a6f40100 8ff40100 52f40100 52f40100 a6f40100
The JSON result is {"title":"💦💏👒👒💦"}
jsonData: 7b227469 746c6522 3a22f09f 92a6f09f 928ff09f 9192f09f 9192f09f 92a6227d

Sigh:
NSString* uniText = mytextField.text;
NSDictionary* jsonDict = #{#"title":uniText};
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJsonObject:jsonDict options:0 error:&error];
if (jsonData == nil) {
NSLog(#"JSON serialization error: %#", error);
}
else {
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"The JSON result is %#", jsonString);
}
If myTextField.text is a valid NSString then no other conversions should be required. NSJSONSerialization will provide all necessary "escaping".

Related

Converting NSData to NSDictionary

I am trying to fetch data from an url https://dl.dropboxusercontent.com/s/2iodh4vg0eortkl/facts.json
I am getting nil while converting nsdata to nsdictionary.
I used the following code. and I am able to log the data as well. but as soon as I convert it into dictionary it is showing nil.What am I missing here?
I tried nsurlsession and afnetworking as well. getting the same error.
NSError *error;
NSString *url_string = [NSString stringWithFormat: DATA_URL];
NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString:url_string]];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"json: %#", json);
You have to convert NSDatainto UTF8 before parsing it using NSJSONSerialization.
NSError* error = nil;
NSString *strISOLatin = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
NSData *dataUTF8 = [strISOLatin dataUsingEncoding:NSUTF8StringEncoding];
id dict = [NSJSONSerialization JSONObjectWithData:dataUTF8 options:0 error:&error];
if (dict != nil) {
NSLog(#"Dict: %#", dict);
} else {
NSLog(#"Error: %#", error);
}
If you are looking for the Swift equivalent of Jayesh Thanki's Objective-C code, here it is,
let str = String(data: d, encoding: .isoLatin1)
let data8 = str?.data(using: .utf8)
let result = try JSONSerialization.jsonObject(with: data8!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary

Deserialise JSON String in Objective C

I received NSData object data from REST API. That contains JSON data which I want to parse.
{
JsonResult = "[{
\"IsAuth\":\"true\",
\"User\":\"
[
{
\\\"userid\\\":\\\"josephH\\\",
\\\"firstname\\\":\\\"joseph\\\",
\\\"lastname\\\":\\\"Henry\\\",
}
]\"}]"
}
This statement gave me the result as a String like below which I am not able to parse as JSON.
myData = [data valueForKey:#"JsonResult"];
"[{
\"IsAuth\":\"true\",
\"User\":\"
[
{
\\\"userid\\\":\\\"josephH\\\",
\\\"firstname\\\":\\\"joseph\\\",
\\\"lastname\\\":\\\"Henry\\\",
}
]\"}]"
When I try to pass this mydata to JSONSerialization the code crashes.
How do I cast the above string to NSDictionary so that I can parse them and use the values of IsAuth and User.?
Code:
[LDService authenticateUser:Uname.text passwordString:Password.text completeBlock:^(NSData * data){
NSError *error;
NSData *jsonData;
NSString *jsonString = nil;
NSMutableDictionary *jsonDict;
if([NSJSONSerialization isValidJSONObject:data])
{
jsonData = [NSJSONSerialization dataWithJSONObject:data
options:kNilOptions
error:&error];
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
NSString *formattedString = [jsonString stringByReplacingOccurrencesOfString:#"\\\"" withString:#"'"];
NSLog(#"Formatted string %#",formattedString);
[jsonDict setObject:formattedString forKey:#"JsonResult"];
NSLog(#"Parsed json %#",jsonDict);
}];
Pass your data as data
NSError *error;
NSString *jsonString = nil;
if([NSJSONSerialization isValidJSONObject:data])
{
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data
options:kNilOptions
error:&error];
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
then replace occurance of #"\\\" with #"'"
NSString *formattedString = [jsonString stringByReplacingOccurrencesOfString:#"\\\"" withString:#"'"];
then use this formattedString.
I have investigates your json file from Json formatter & Validator, there are lots of error in your json file, so first check your file from this validator and this formatter gives you error with description. Re-build your json file, if you still getting any problem then ask.

Best way to display JSON (well formatted) in UITextView or UIWebView in iOS

I need to display JSON in my iPhone app. Currently I am getting unformatted JSON - like one big string with no indentation.
What would be the best way to display this?
Thanks,
to get formatted JSON string.
The solution is to create JSON Object from JSON string,
and then convert the JSON object back to JSON String, using .PrettyPrinted option.
The code is
let jsonString = "[{\"person\": {\"name\":\"Dani\",\"age\":\"24\"}},{\"person\": {\"name\":\"ray\",\"age\":\"70\"}}]"
var error: NSError?
//1. convert string to NSData
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
//2. convert JSON data to JSON object
let jsonObject:AnyObject = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error)!
//3. convert back to JSON data by setting .PrettyPrinted option
let prettyJsonData = NSJSONSerialization.dataWithJSONObject(jsonObject, options: .PrettyPrinted, error: &error)!
//4. convert NSData back to NSString (use NSString init for convenience), later you can convert to String.
let prettyPrintedJson = NSString(data: prettyJsonData, encoding: NSUTF8StringEncoding)!
//print the result
println("\(prettyPrintedJson)")
The result will look like this
Objective-C code
NSString *jsonString = #"[{\"person\": {\"name\":\"Dani\",\"age\":\"24\"}},{\"person\": {\"name\":\"ray\",\"age\":\"70\"}}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:&error];
NSData *prettyJsonData = [NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:&error];
NSString *prettyPrintedJson = [NSString stringWithUTF8String:[prettyJsonData bytes]];
NSLog(#"%#", prettyPrintedJson);
here's the Objective-C code.
NSString+PrettyPrint.h
#interface NSString (PrettyPrint)
+ (NSString * _Nonnull)prettifiedJsonStringFromData:(nullable NSData *)data;
+ (NSString * _Nonnull)prettifiedStringFromDictionary:(nullable NSDictionary *)dictionary;
#end
NSString+PrettyPrint.m
#import "NSString+PrettyPrint.h"
#implementation NSString (PrettyPrint)
+ (NSString *)prettifiedStringFromDictionary:(nullable NSDictionary *)dictionary {
if (dictionary == nil) { return #"nil"; }
NSMutableString *returnStr = [NSMutableString stringWithString:#"[ \n"];
for (NSString *key in dictionary) {
[returnStr appendFormat:#" %#: %#,\n", key, [dictionary valueForKey:key]];
}
[returnStr appendFormat:#"]"];
return returnStr;
}
+ (NSString *)prettifiedJsonStringFromData:(nullable NSData *)data {
if (data == nil) { return #"nil"; }
NSData *jsonData;
NSError *error = nil;
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
if (jsonObject == nil) {
return #"nil (json object from data)";
} else {
BOOL isValidJsonObject = [NSJSONSerialization isValidJSONObject:jsonObject];
if (isValidJsonObject) {
NSData *finalData = [NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:&error];
//TODO: error description
NSString *prettyJson = [[NSString alloc] initWithData:finalData encoding:NSUTF8StringEncoding];
return prettyJson;
} else {
return [NSString stringWithFormat:#"%#\n%#", jsonStr, #" (⚠️ Invalid json object ⚠️)\n"];
}
}
}
#end
then call methods when u need to use them.
ex1. Print NSData for body, response ...etc
NSLog(#"body: %#", [NSString prettifiedJsonStringFromData:[request HTTPBody]]);
ex2. Print NSDictionary
NSLog(#"headers: %#", [NSString prettifiedStringFromDictionary:[request allHTTPHeaderFields]]);
Probably you'll get these results in log.
Bear in mind, if you are dealing with Encodable objects you can use JSONEncoder for pretty printing.
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let jsonData = try? encoder.encode(obj) else {
return
}
let text = String(decoding: jsonData, as: UTF8.self)

iOS Error Parsing JSON

I am new to iOS. I have this JSON data that I needed to parse:
{
"allseries":[
{
"type":"HR",
"title":"Heart Rate",
"xLabel":"Time",
"yLabel":"Beats per Min",
"defaultUnit":"BPM",
"url":"info/info?user=admin%40korrent.com&type=HR",
"size":18,
"firstTs":1406755651,
"lastTs":1406841254
},
{
"type":"TEMP",
"title":"Temperature",
"xLabel":"Time",
"yLabel":"Temperature",
"defaultUnit":"F",
"url":"info/info?user=admin%40korrent.com&type=TEMP",
"size":6,
"firstTs":1406854147,
"lastTs":1406854283
}
],
"status":"OK"
}
So far this is my code:
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#"--> async response data (string): %#", dataReceived);
NSData *jsonData = [dataReceived dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:&jsonError];
NSLog(#"JSON key and value %#", [dict description]);
NSLog(#" %# ", dict[#"allseries"]);
NSString *jsonString=dict[#"allseries"];
if (_programState == 4){
NSLog(#"state is 4");
NSLog(#"%#",jsonString);
NSData *Data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
However, the code throws invalid argument exception for this line:
NSData *Data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
Further more, jsonString seems totally "inoperable". I cannot split it, append strings to it etc. So what's wrong?
// The following two lines are just for logging and otherwise are not needed.
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#"--> async response data (string): %#", dataReceived);
// Deserialize the JSON data into a dictionary
NSError *jsonError;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData: _responseData options:nil error:&jsonError];
NSLog(#"JSON key and value %#", dict);
// Get the array from the dictionary element "allseries".
NSArray *jsonArray = dict[#"allseries"];
NSLog(#"jsonArray: %#", jsonArray);
Here jsonArray is the array of dictionaries for "allseries" from the JSON
What you did is totally, totally wrong.
dict[#allseries] is not an NSString. It is an NSArray with two elements, and both its elements are NSDictionary.

With AFNetworking how can I read the error message contained in request.responseString

NSLog(#"%#", request.responseString);
This gives me output of {"errors":{"email":["is already taken"]}}.
I would like to save email and the message string "is already taken" into a string to display in an alert. How can I access those two items into two strings?
The response string is the raw output from the server. In this case it is JSON encoded. You can either use one of the AFNetworking JSON-specific classes (i.e. AFJSONRequestOperation) to get the response back as a JSON object, or parse it yourself using NSJSONSerialization. I would suggest using AFJSONRequestOperation.
NSData *data = [request.responseString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *str = [[json objectForkey:#"errors"] objectForKey:#"email"][0];
I used the following, seems a tiny bit more robust:
[requestOperation setCompletionBlockWithSuccess:success failure:^(AFHTTPRequestOperation *operation, NSError *error) {
id response = error.userInfo;
if (response && [response isKindOfClass:[NSDictionary class]]) {
NSDictionary *responseDictionary = (NSDictionary *)response;
// AFNetworking hides the actual error response under this key
if ([responseDictionary valueForKey:NSLocalizedRecoverySuggestionErrorKey]) {
id suggestedRecovery = [responseDictionary valueForKey:NSLocalizedRecoverySuggestionErrorKey];
if ([suggestedRecovery isKindOfClass:[NSString class]]) {
// Try to json decode string
id json = [NSJSONSerialization JSONObjectWithData:[suggestedRecovery dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
if (json && [json isKindOfClass:[NSDictionary class]]) {
responseDictionary = json;
}
}
}
// .. extract error message out of responseDictionary
}
}];
NSData *responseData = [[error userInfo] objectForKey:#"data"];
if ([responseData length] > 0)
{
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", str);
}

Resources