JSON Objective-C Parsing Fail - ios

I have written the following code but I keep on getting nil. I have tried many different variations of this but I am failing exceptionally hard.
This is what I am getting from the server.
Two objects.
[{"description":"yolo.","name":"ye","id":1},{"description":"sMITH","name":"John","id":2}]
Any help would be greatly appreciated...... Thanks.
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSArray *jsonObjects = [jsonParser objectWithData:response];
NSMutableString *yolo = [[NSMutableString alloc] init];
for ( int i = 0; i < [jsonObjects count]; i++ ) {
NSDictionary *jsonDict = [jsonObjects objectAtIndex:i];
NSString *IDID = [jsonDict objectForKey:#"id"];
NSString *name = [jsonDict objectForKey:#"name"];
NSLog(#"ID: %#", IDID); // THIS DISPLAYS
[yolo appendString: IDID]; // THIS seems to be causing the new error...
[yolo appendString:#": "];
[yolo appendString: name];
NSLog(#"%#", yolo); // RETURNS NIL
}
EDIT:
currently my new error is...
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[NSDecimalNumber length]:
unrecognized selector sent to instance 0x81b89f0'

Looks like your [jsonDict objectForKey:#"id"] is an NSNumber(or NSDecimalNumber) and not an NSString. You should change the line NSString *IDID = [jsonDict objectForKey:#"id"]; to,
id myObject = [jsonDict objectForKey:#"id"];
NSString *IDID = nil;
if ([myObject isKindOfClass:[NSNumber class]]) {
IDID = [[jsonDict objectForKey:#"id"] stringValue];
} else {
IDID = [jsonDict objectForKey:#"id"];
}
This error appeared now since earlier you were not initializing NSMutableString *yolo and you were using appendString: on a nil object. Since now it is initialized as NSMutableString *yolo = [[NSMutableString alloc] init]; it is trying to call appendString on NSMutableString object which accepts only NSString type as its inputs where as you are passing an NSNumber in it. length is a method which appendString: internally calls. So you need to change this as well.

You never initialize yolo, so it's just nil the whole time you're calling -appendString: on it. Try this:
NSMutableString *yolo = [NSMutableString string];

Have you tried initializing the NSMutableString?
NSMutableString *yolo = [[NSMutableString alloc] init];

It looks like you are not really checking the type of the data coming to your app via your JSON feed. This might be the case of random crashes when users actually use your app. It might be also a reason for rejection to the App Store, is such crashes happen during your App's review.
You should be checking the type of all objects you receive from JSON, before calling methods on them :)
By implementing best practices you will have a stable and usable app. Build data models to validate your data. You can also you a JSON data model framework like JSONModel: http://www.jsonmodel.com/

It's obvious from your data that "id" is not a string, but a number. Assigning a pointer to an NSString* doesn't magically convert it to an NSString*. And it's obvious from the exception that you got that some object is an NSDecimalNumber when you thought it would be an NSString.
So: IDID is an NSNumber*, and pretending it is an NSString* will lead to crashes.

Related

Corruption of NSString or encoding issue in Objective C

Please see code below:
+ (void)splashDataFromJSON:(NSData *)objectNotation error:(NSError **)error
{
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
if (localError != nil) {
*error = localError;
}
NSMutableArray* btms = [[NSMutableArray alloc] init];
NSMutableDictionary* btmManufacturerResolutionDictionary = [[BTMCache sharedManager] btmManufacturerResolutionDictionary];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", parsedObject.count);
NSString* imageBaseUrl = [[parsedObject valueForKey:#"general"] valueForKey:#"image_base_url"];
imageBaseUrl = [imageBaseUrl stringByAppendingString:#"hdpi/"];
NSString* splashImageName = [[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"img"];
NSString* splashAdvertiserURL = [[[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"url"] copy];
NSMutableString* appendedString = [[NSMutableString alloc] init];
for(int i =0 ;i<[splashAdvertiserURL length]; i++) {
char character = [splashAdvertiserURL characterAtIndex:i];
printf(&character);
sleep(0.1);
if (character != "!")
{
[appendedString appendFormat:#"%c", character];
}
}
[[SplashData sharedManager] setSplashAdvertiserURL:appendedString];
[[SplashData sharedManager] setSplashImageName:splashImageName];
splashAdvertiserURL = [[SplashData sharedManager] splashAdvertiserURL];
}
The point of interest is in splashAdvertiserURL. When I receive this data and print it out using po, it comes out as "https://radar.com/ref/go/84/". This is fine and what was expected. When I look at the incoming data in JSONLint it looks like this:
"general": {
"image_base_url": "https:\/\/radar.com\/img\/manufacturers\/",
"splash": {
"img": "image1.png",
"url": "https:\/\/radar.com\/ref\/go\/84\/"
}
},
As you can see, further on I put the NSString into a singleton with an NSString property. Nothing abnormal here. I then proceed to retrieve it to see that all is ok. Further to this the program continues. In another class I wish to retrieve this information, and when I try and do that, it throws EXC_BAD_ACCESS. There appears to be garbage in there.
I then put in a loop in the code as you can see to print out the characters one at a time. Very curiously, when I print that out using po I get:
https://
r
a
d
ar.com/ref/go/8 4!/"
Exactly in that format. If I then proceed to hardcode the string https://radar.com/ref/go/84/ - including escape characters and everything, then all works fine. No issues. If I handle a normal string incoming without escape characters it stores fine in the singleton as well, no issue. enter code here
I am pretty stumped here as to what is going on. Can someone assist?
Thank you
For URL you received as string you need to encode before use it to in your app. Have a look at below code:
NSString *sampleUrl = #"https:\/\/radar.com\/ref\/go\/84\/";
NSString *encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];

Save json object in sqlite like text and retransform to dictionary on read

I want to save a Json Object in a field (text) sqlite and then read it again with a select and retransform to NSDictionary or NSMutableArray to parse the key/values
This is how i save actually in the sqlite DB
As you see, is a song object from the iTunes api. I want to read that object and parse it.
This is how i make the select query and save it in a NSDictionary while i filling and NSMutableArary
globals.arrayMyPlaylists = [[NSMutableArray alloc] init];
// Form the query.
NSString *query = #"select * from myplaylists";
// Get the results.
NSArray *listas = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
for (int i = 0; i < listas.count; i++) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
NSLog(#"lista %d %# %#", i, listas[i][0], listas[i][1]);
[dictionary setObject:listas[i][0] forKey:#"id"];
[dictionary setObject:listas[i][1] forKey:#"nombre"];
NSString *query2 = [NSString stringWithFormat:#"select cancion from canciones where idplaylist = %#", listas[i][0]];
NSArray *canciones = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query2]];
[dictionary setObject:canciones forKey:#"canciones"];
[globals.arrayMyPlaylists addObject:dictionary];
dictionary = nil;
}
When i try to read it in the cellForRowAtIndexPath method
NSArray *canciones = [[NSArray alloc] initWithArray:[[globals.arrayMyPlaylists objectAtIndex:indexPath.row] valueForKey:#"canciones"]];
and try to get the value for the key artworkUrl100
[cell.tapa1 sd_setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#", [[canciones objectAtIndex:i] valueForKey:#"artworkUrl100"]]] placeholderImage:nil];
i get the error
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x7ff575810600> valueForUndefinedKey:]: this class is not key value coding-compliant for the key artworkUrl100.'
i understand i'm messing up in some way with dictionarys/nsmutablearrays. I need some help. Thanks!
EDIT: this is how i save the data in the DB
NSString *query = [NSString stringWithFormat:#"insert into canciones (idplaylist, cancion) values ('%#', '%#')", [[globals.arrayMyPlaylists objectAtIndex:indexPath.row] valueForKey:#"id"], self.elementoSeleccionado];
[self.dbManager executeQuery:query];
self.elementoSeleccionado is the NSMutableArray with the "cancion" object and it's saved like it's shows the first image.
EDIT 2: this is what i get trying schmidt9's answer
EDIT 3: OK, i have the json string escaped. How i have to parse now?
You should parse your output first with NSJSONSerialization:
NSString *query2 = [NSString stringWithFormat:#"select cancion from canciones where idplaylist = %#", listas[i][0]];
NSArray *canciones = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query2]];
// I suppose your array canciones should contain only one song object ...
NSError *error = nil;
id object = [NSJSONSerialization JSONObjectWithData:canciones[0] options:0 error:&error];
if(error) {
// handle error ...
}
if([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *result = object;
[dictionary setObject:result forKey:#"canciones"];
}
Edit
Saving to database
2 options:
- if you get a prepared json string, save it directly to DB, but before you should escape quotes. See eg. here
- if you have NSDictionary:
- (NSString*)JSONStringWithDictionary:(NSDictionary*)dictionary prettyPrinted:(BOOL)prettyPrinted
{
NSJSONWritingOptions options = (prettyPrinted) ? NSJSONWritingPrettyPrinted : 0;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:options error:nil];
return [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
}
After that you should escape the string too.

iOS - Converting UTF8 data from backend and displaying incorrectly

I am writing an iOS application that receives data from the backend. I parse the NSData object (objectNotation) as below.
Everything works fine until I receive a special character in the one entity, which is:
"Test já"
When I receive this and I debug parsedObject, it shows "type" to be "Test j\U00e1"
So this is obviously some Unicode/UTF8 issue. I then proceeded to look all over stack overflow, and found various potential solutions to this and tried them all, to no avail.
NSString *stringTest = [[NSString alloc] initWithData:objectNotation
encoding:NSUTF8StringEncoding]; --> does not work
NSString * test2 = [NSString
stringWithCString:[stringTest cStringUsingEncoding:NSUTF8StringEncoding]
encoding:NSASCIIStringEncoding]; --> does not work
I have tried every single encoding that Obj has to offer, and it either returns the character as \U00e1, or nil, or a bunch of garbage.
I have battled with this for hours so it is a good time to post now. I appreciate any assistance. Thank you.
Code is below:
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
NSMutableArray *btms = [[NSMutableArray alloc] init];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", results.count);
NSLog(#"Count %d", parsedObject.count);
[parsedObject enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
BTM *btm = [[BTM alloc] init];
NSLog(#"%# => %#", key, value);
btm.number = key;
btm.latitude = [value valueForKey:#"lat"];
btm.longitude = [value valueForKey:#"long"];
NSString* temp = [value valueForKey:#"type”];
}
Set "application/x-www-form-urlencoded; charset=UTF-8" as 'Content-Type' while receiving data from the backend.
[requestUrl setValue:#"application/x-www-form-urlencoded; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];

How to parse integer value to Json iOS?

I was passed NSstring it is coming properly data into uitableview but when I am parsing integer value it showing exception Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: -[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0x744e9d0
This is my code
(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData options:kNilOptions error:&error];
NSArray * values=[json objectForKey:#"loans"];
NSLog(#"Array: %#",values);
for (NSDictionary *file in values)
{
NSNumber *fileTitle=[file objectForKey:#"id"];
// NSString *fileTitle = [file objectForKey:#"sector"];
[titles addObject: fileTitle];
}
[self.mainTableView reloadData];
}
You are assigning string value to NSNumber type.
Try to use this
NSString *fileTitle=[file objectForKey:#"id"];
[titles addObject: fileTitle];
and use string value.
[[titles addObject: fileTitle] stringValue];
I guess you are doing something like this in your -tableView: cellForIndexPath:
UITableViewCell *cell = [...];
cell.titleLabel.text = titles[indexPath.row];
You can only use NSString for -[UILabel setText:] method.
Convert your NSNumber to NSString with a simple -[NSNumber stringValue] or using NSNumberFormatter.
Everything seems ok. Just replace
NSNumber *fileTitle=[file objectForKey:#"id"];
by NSString *fileTitle = [file objectForKey:#"id"];

iOS FGallery objective c assigning string value dynamically

It is a bit complicated to explain my problem. I am using FGallery library https://github.com/gdavis/FGallery-iPhone and especially its feature to load images from URL addresses. When I hardcode the URL path it works super, but wen I pass a string variable to the class which I have created it doesn't work. I tried to debug it and it seems that everything is ok, there is a string assigned to the variable and everything, but do not show the picture. I am doing this in a loop and using ARC.
-(void) loadSoftia
{
//======================================================================================
//THIS WORKS CORRECTLY!!!
wcSofia = [[NSMutableArray alloc] init];
Webcam *s1 = [[Webcam alloc]init];
s1.description=#"Sofia";
s1.location = #"http://www.ampthillweatherstation.info/currentweather/webcamimage.jpg";
[wcSofia addObject:s1];
//======================================================================================
NSMutableString *urlGetOthersLocations =[NSMutableString stringWithFormat:#"http://%#/WebHandlers/%#", #"192.168.188.204", #"BGCam.ashx"];
ServerResponse *serverResponseOthersLocations = [HelperViewController getJsonDataFromTheServer:urlGetOthersLocations];
if(serverResponseOthersLocations.data!=nil)
{
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:serverResponseOthersLocations.data
options:NSJSONReadingMutableLeaves|NSJSONReadingMutableContainers
error:nil];
[wcSofia removeAllObjects];
Webcam *wc;
int i=0;
for (NSDictionary *locationsDic in dic){
NSString *key;
for ( key in locationsDic) {
NSLog(#"%# = %#", key, [locationsDic objectForKey: key]);
}
NSLog(#"%#", [locationsDic objectForKey:#"URL"]);
NSLog(#"%# = %#", locationsDic, [locationsDic objectForKey: locationsDic]);
NSString *url =[locationsDic objectForKey:#"URL"];
// NSLog(#"%#", url);
NSMutableString* theString = [NSString stringWithFormat:#"%i ",i];
wc = [[Webcam alloc]initWithLocation: [NSString stringWithFormat:#"%#", url] withDescription:#"description"];
wc.location = url;//DOESNT WORK!
wc.description =#"София";// theString;//[NSString stringWithFormat:#"%#", #"aa"]; // #"София";
wc.location = #"http://media.borovets-bg.com/cams/channel?channel=61";//IT WORKS BECAUSE IT IS HARDCODED
if(wcSofia!=nil)
{
[wcSofia addObject:wc];
NSLog(#"%#", wc.location);
}
i++;
}
}
}
I have commented a section of the code which works and which doesn't.
I suppose that you are not going to need the whole program, because it make requests to my local web server to get the URL addresses and descriptions, but trust me this thing works perfect.
Thank you for your help in solving that mystery.
Edit:
Complete source Code: https://dl.dropboxusercontent.com/u/46512232/FGallery.zip

Resources