How can I use NSJSONSerialization with special characters like "ñ"? - ios

I'm using NSJSONSerialization to parse Google suggestions.
The query "f" returns these suggestions:
["f",["facebook","flipkart","fox news","forever 21","friv","fandango","fedex","fitbit","food near me","flights"]]
The parser works fine but when there are special characters like "ñ" for the query "fac":
["fac",["facebook","facebook search","fac","facebook app","facebook lite","facebook login","facebook logo","facebook messenger","facetime","facebook en español"]]
It throws an exception:
Error Domain=NSCocoaErrorDomain Code=3840 "Unable to convert data to string around character 139." UserInfo={NSDebugDescription=Unable to convert data to string around character 139.}
Any ideas? I tried all different reading options but none of them works.
#pragma mark -
- (void)request:(NSString *)text
{
NSMutableArray *items = [[NSMutableArray alloc] init];
NSString *query = [text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *languageCode = [[NSLocale preferredLanguages] firstObject];
if (!languageCode) {
languageCode = #"en";
}
NSString *URLString = [NSString stringWithFormat:#"http://suggestqueries.google.com/complete/search?q=%#&client=firefox&hl=%#", query, languageCode];
NSError *downloadError = nil;
NSData *JSONData = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLString] options:0 error:&downloadError];
if (!downloadError && JSONData) {
NSError *parseError = nil;
id object = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableContainers error:&parseError];
if (!parseError && object) {
if ([object isKindOfClass:[NSArray class]]) {
NSArray *objects = (NSArray *)object;
NSArray *texts = [objects objectAtIndex:1];
for (NSString *text in texts) {
SNGoogleItem *item = [[SNGoogleItem alloc] initWithText:text];
[items addObject:item];
}
[_delegate google:self didRespondWithItems:items];
}
else {
[_delegate google:self didRespondWithItems:items];
}
}
else {
[_delegate google:self didRespondWithItems:items];
}
}
else {
[_delegate google:self didRespondWithItems:items];
}
}

JSONSerialization supports all the encodings in JSON spec, says Apple documentation.
You didn't provide much info about the encoding scheme of your data but I guess you use nonLossyASCII or something like that, which is not supported by JSONSerialization.
Here is how I convert data to/from JSON:
let rawString = "[[\"facebook en español\"]]"
// if I use String.Encoding.nonLossyASCII below, I get the error you are getting
let data = rawString.data(using: String.Encoding.utf8)
let dict = try! JSONSerialization.jsonObject(with: data!)
let convertedData = try! JSONSerialization.data(withJSONObject: dict)
let convertedString = String(data: convertedData, encoding: String.Encoding.utf8)!
// now convertedString contains "ñ" character

This will convert whatever encoding used to UTF8:
NSData *JSONData = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLString] options:0 error:&downloadError];
NSString *convertedJSONString; BOOL usedLossyConversion;
[NSString stringEncodingForData:JSONData encodingOptions:0 convertedString:&convertedJSONString usedLossyConversion:&usedLossyConversion];
NSData *convertedJSONData = [convertedJSONString dataUsingEncoding:NSUTF8StringEncoding];
Now, it works!

Related

Get values from NSDictionary

Hi I'm new to iOS development. I want to get response and add those values to variable.
I tried it but I'm getting below response. I don't understand why there is slashes in this response.
#"[{\"VisitorID\":\"2864983a-e26b-441a-aedf-84e2a1770b8e\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kanasalingam\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]},{\"VisitorID\":\"133bc108-b3bf-468a-9397-e1b0dba449db\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kumar\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]}]"
I tried this :
- (void) sendOtherActiveChats:(NSDictionary *) chatDetails{
NSLog(#"inside sendOtherActiveChats");
NSLog(#"otherDetails Dictionary : %# ", chatDetails);
NSString *VisitorID = [chatDetails objectForKey:#"VisitorID"];
NSString *ProfileID = [chatDetails objectForKey:#"ProfileID"];
NSString *CompanyID = [chatDetails objectForKey:#"CompanyID"];
NSString *VisitorName = [chatDetails objectForKey:#"VisitorName"];
NSString *OperatorName = [chatDetails objectForKey:#"OperatorName"];
NSString *isocode = [chatDetails objectForKey:#"isocode"];
NSLog(#"------------------------Other Active Chats -----------------------------------");
NSLog(#"VisitorID : %#" , VisitorID);
NSLog(#"ProfileID : %#" , ProfileID);
NSLog(#"CompanyID : %#" , CompanyID);
NSLog(#"VisitorName : %#" , VisitorName);
NSLog(#"OperatorName : %#" , OperatorName);
NSLog(#"countryCode: %#" , isocode);
NSLog(#"------------------------------------------------------------------------------");
}
Can some one help me to get the values out of this string ?
You are getting Array of Dictionary in response, but your response is in string so you convert it to NSArray using NSJSONSerialization like this way for that convert your response string to NSData and after that use that data with JSONObjectWithData: to get array from it.
NSString *jsonString = #"[{\"VisitorID\":\"2864983a-e26b-441a-aedf-84e2a1770b8e\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kanasalingam\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]},{\"VisitorID\":\"133bc108-b3bf-468a-9397-e1b0dba449db\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kumar\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]}]";
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
NSMutableArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&e];
Now loop through the array and access the each dictionary from it.
for (NSDictionary *dic in jsonArray) {
NSLog(#"%#",[dic objectForKey:#"VisitorID"]);
... and so on.
}
First you need to parse your string.
NSString *aString = #"[{\"VisitorID\":\"2864983a-e26b-441a-aedf-84e2a1770b8e\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kanasalingam\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]},{\"VisitorID\":\"133bc108-b3bf-468a-9397-e1b0dba449db\",\"ProfileID\":\"69c02265-abca-4716-8a2f-ac5d642f876a\",\"CompanyID\":null,\"VisitorName\":\"kumar\",\"OperatorName\":\"baman\",\"Image\":null,\"isocode\":\"lk\",\"CurrentOperator\":[\"69c02265-abca-4716-8a2f-ac5d642f876a\"]}]";
NSData *data = [aString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"%#",[[json objectAtIndex:0] objectForKey:#"VisitorID"]);
So you have JSON string and array of 2 objects. So write following code
This will convert JSON string to Array
NSData *myJSONData = [YOUR_JSON_STRING dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSMutableArray *arrayResponse = [NSJSONSerialization JSONObjectWithData:myJSONData options:NSJSONReadingMutableContainers error:&error];
Now use for loop and print data as
for (int i = 0; i < arrayResponse.count; i++) {
NSDictionary *dictionaryTemp = [arrayResponse objectAtIndex:i];
NSLog(#"VisitorID : %#",[dictionaryTemp valueForKey:#"VisitorID"]);
NSLog(#"ProfileID : %#",[dictionaryTemp valueForKey:#"ProfileID"]);
NSLog(#"CompanyID : %#",[dictionaryTemp valueForKey:#"CompanyID"]);
NSLog(#"VisitorName : %#",[dictionaryTemp valueForKey:#"VisitorName"]);
}
Now there are good chances that you will get NULL for some keys and it can cause in crash. So avoid those crash by using Null validations.

Any tools to beautify the nested NSDictionary result

Is there any tools, including online service and macOs app, to beautify the nested NSDictionary result like this?
{
id = 1;
testName = my name;
createDate = 20021023;
likeNumber = 0;
statusList = ({
appleId = 1;
orangeName = 81;
itsStatus = YES;
});
text = test;
type = Text;
},
I mean collapse(close and open) the tree nodes easily.
Currently ,there are many online tools for this purpose when it comes to JSON like jsonformatter.
As Fonix mentioned, the best way to convert NSDictionary to JSON and then use JSON tools for this purpose:
+(NSString *)dictionaryToJson:(NSDictionary *)dictionary {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
jsonString = [error localizedDescription];
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return jsonString;
}

Converting NSString to JSON with NSJSONSerialization is not working

I have this function:
- (void)checkLogin:(NSString *)pLogin andPassword:(NSString*) pPassword {
//Create the data object.
NSMutableDictionary *tLoginAndPasword = [NSMutableDictionary dictionaryWithObjectsAndKeys:pLogin,#"Login",pPassword,#"Password", nil];
NSMutableDictionary *tData = [NSMutableDictionary dictionaryWithObjectsAndKeys:[_Util serializeDictionary:tLoginAndPasword],#"Data", nil];
//Call the login method.
NSData *tResponse = [_Util getLogin:tData];
if (tResponse != Nil) {
_oLabelErrorLogin.hidden = YES;
[_Util setUser:pLogin andPassword:pPassword];
NSMutableDictionary *tJSONResponse =[NSJSONSerialization JSONObjectWithData:tResponse options:kNilOptions error:nil];
NSString *tPayload = [tJSONResponse objectForKey:#"Payload"];
if([[tJSONResponse objectForKey:#"StatusCode"] isEqual: #"424"]) {
//Set global values.
NSData *tPayloadData = [tPayload dataUsingEncoding:NSUTF8StringEncoding];
if ([NSJSONSerialization isValidJSONObject:tPayloadData]) {
_Payload = [NSJSONSerialization JSONObjectWithData:tPayloadData options:kNilOptions error:nil];
_RowCount = _Payload.count;
} else {
NSLog(#"JSON Wrong String %#",tPayload);
}
} else if([[tJSONResponse objectForKey:#"StatusCode"] isEqual: #"200"]){
_Payload = Nil;
}
} else {
//Set global values.
_Payload = Nil;
_oLabelErrorLogin.hidden = NO;
//Clear login data.
_oLogin.text = #"";
_oPassword.text = #"";
[_Util setUser:#"" andPassword:#""];
}
}
The JSON response looks like this:
{
"Payload": "{\"UserName\":\"Marco Uzcátegui\",\"Clients\":[{\"UserProfileId\":4,\"ProfileName\":\"Platform Administrator\",\"ClientName\":\"Smart Hotel Platform\",\"InSession\":true},{\"UserProfileId\":5,\"ProfileName\":\"Administrator\",\"ClientName\":\"La Moncloa de San Lázaro\",\"InSession\":false},{\"UserProfileId\":6,\"ProfileName\":\"Administrator\",\"ClientName\":\"Jardín Tecina\",\"InSession\":false}]}",
"StatusCode": "424",
"StatusDescription": null
}
As you can see, I have a escaped string inside "Payload" that is a correct JSON, so I want to generate another NSMutableDictionary with that string, so I'm doing this:
NSData *tPayloadData = [tPayload dataUsingEncoding:NSUTF8StringEncoding];
if ([NSJSONSerialization isValidJSONObject:tPayloadData]) {
_Payload = [NSJSONSerialization JSONObjectWithData:tPayloadData options:kNilOptions error:nil];
_RowCount = _Payload.count;
} else {
NSLog(#"JSON Wrong String %#",tPayload);
}
So I'm creating an NSData from the NSString and asking if is valid, it always returns false.
I have tried to replace the "\" from the string and is not working.
[tPayload stringByReplacingOccurrencesOfString:#"\\\"" withString:#""]
I have tried to create a NSMutableDictionary with the string, but the result is not a dictionary.
NSMutableDictionary *tPayload = [tJSONResponse objectForKey:#"Payload"];
I'm kind of lost here.
Any help will be appreciated.
Regards.
The issue is this line
[NSJSONSerialization isValidJSONObject:tPayloadData]
From the documentation of isValidJSONObject
Returns a Boolean value that indicates whether a given object can be
converted to JSON data.
given object means an NSArray or NSDictionary but not NSData
Remove that check and implement the error parameter in JSONObjectWithDataoptions:error:
The method NSJSONSerialization.isValidJSONObject: checks if an object (e.g. a NSDictonary or NSArray instance) can be converted to JSON. It doesn't check if a NSData instance can be converted from JSON. For NSData, it will always return false.
So just call NSJSONSerialization.JSONObjectWithData:options: and check the result instead.

NSString JSON - filtering through data

I am converting JSON data in to NSString using below code:
NSString *json_string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data AS STRING %#", json_string);
it returns NSString in this format:
Data AS STRING
{
"success": true,
"terms": "https://currencylayer.com/terms",
"privacy": "https://currencylayer.com/privacy",
"timestamp": 1446673809,
"source": "USD",
"quotes": {
"USDAED": 3.672993,
"USDAFN": 64.980003,
"USDALL": 127.164497,
"USDAMD": 474.480011,
"USDANG": 1.790326,
"USDAOA": 135.225006,
"USDARS": 9.536025,
"USDAUD": 1.398308,
"USDAWG": 1.79,
"USDAZN": 1.04625,
"USDBAM": 1.800851,
"USDBBD": 2,
"USDBDT": 78.666946,
"USDBGN": 1.80115,
"USDBHD": 0.37727,
"USDBIF": 1562.5,
"USDBMD": 1.00005,
"USDBND": 1.403198,
"USDBOB": 6.899293,
"USDBRL": 3.80025,
"USDBSD": 0.999335,
"USDBTC": 0.002372,
"USDBTN": 65.495003,
"USDBWP": 10.55195,
"USDBYR": 17415,
"USDBZD": 1.994983,
"USDCAD": 1.315225,
"USDCDF": 929.999946,
"USDCHF": 0.99331,
"USDCLF": 0.024598,
"USDCLP": 692.094971,
"USDCNY": 6.33525,
"USDCOP": 2837.080078,
"USDCRC": 534.015015,
"USDCUC": 0.99991,
"USDCUP": 0.99978,
"USDCVE": 101.349503,
"USDCZK": 24.907012,
"USDDJF": 177.595001,
"USDDKK": 6.8657,
"USDDOP": 45.400002,
"USDDZD": 107.014999,
"USDEEK": 14.325002,
"USDEGP": 8.029699,
"USDERN": 15.279969,
"USDETB": 21.022499,
"USDEUR": 0.920471,
"USDFJD": 2.157498,
"USDFKP": 0.648499,
"USDGBP": 0.650132,
"USDGEL": 2.395014,
"USDZWL": 322.355011
}
}
I need to get value of "USDGBP" from that string. How can I do that? Preferably stored as double.
Rather than converting it into NSString try converting it in NSDictionary using
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
then you can retrieve value of USDGBP like
double usdgbp = [jsonDict[#"quotes"][#"USDGBP"] doubleValue];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
double usdgbpValue = [jsonDict[#"quotes"][#"USDGBP"] doubleValue];
you can find the value in the string simply extracting a string between 2 string.
NSString *jsonStr = #"long json string";
NSRange str1 = [jsonStr rangeOfString:#"\"USDGBP\":"];
NSRange str2 = [jsonStr rangeOfString:#","];
NSRange strSub = NSMakeRange(str1.location + str1.length, str2.location - str1.location - str1.length);
NSString *valueForUSDGBP = [jsonStr substringWithRange:strSub];
You should use NSJSONSerialization
NSData *jsonData = your data ... ;
NSError *theError = nil;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&theError];
if (theError) {
NSLog(#"%#", theError);
}
else {
double theValue = [jsonDict[#"quotes"][#"USDGBP"] doubleValue];
}
If you'd like to have much fun, use NSScanner to parse the string ;)

How should I read the data from a json string? iphone

I have in a NSString "[{"van" : 1,312, "vuan":12,123}] and in order to get this values for every key, I am doing this:
NSData *data1 = [jsonResponse1 dataUsingEncoding:NSUTF8StringEncoding];
jsonArray = [NSJSONSerialization JSONObjectWithData:data1 options:kNilOptions error:&err];
self.van = [NSMutableArray arrayWithCapacity:1];
self.vuan = [NSMutableArray arrayWithCapacity:1];
for (NSDictionary *json in jsonArray) {
NSString * value = [json objectForKey:#"van"];
[self.van addObject:value];
lbl1.text = value;
NSString * value1 = [json objectForKey:#"vuan"];
[self.vuan addObject:value1];
lbl4.text = value1;
}
May be I don't have to use an array and instead to convert the NSData directly in a NSDictionary.
Anyway, I don't understand why jsonArray is nil, although jsonResponse1 contains the values I have written above.
EDIT: My boss have written the json string wrong. Thank you all for your suggestions!:)
Your JSON is invalid. Fix it. This site is your friend.
http://jsonlint.com/
You need to code more defensively and you need to report errors as they are found.
Firstly check if the JSON parsing failed and if so report the error:
NSData *data1 = [jsonResponse1 dataUsingEncoding:NSUTF8StringEncoding];
jsonArray = [NSJSONSerialization JSONObjectWithData:data1 options:kNilOptions error:&err];
if (jsonArray == nil)
{
NSLog(#"Failed to parse JSON: %#", [err localizedDescription]);
return;
}
Secondly if those keys are not in the JSON, objectForKey: will return nil and when you attempt to add that to the arrays, it will throw an exception, which is something you want to avoid:
for (NSDictionary *json in jsonArray) {
NSString * value = [json objectForKey:#"van"];
if (value != nil)
{
[self.van addObject:value];
lbl1.text = value;
}
else
{
NSLog(#"No 'van' key in JSON");
}
NSString * value1 = [json objectForKey:#"vuan"];
if (value1 != nil)
{
[self.vuan addObject:value1];
lbl4.text = value1;
}
else
{
NSLog(#"No 'vuan' key in JSON");
}
}
So in summary: runtime errors will occur so you need to ensure you handle them. When they occur you need to report them with as much information possible so that you can diagnose and fix them.

Resources