Adding 2 keyvalues to list from JSON object - iphone

I want to append 2 key values from JSON object to my list in iPhone app. Below is my code for that,
SBJsonParser *jsonParser = [[[SBJsonParser alloc] init] autorelease];
NSString *jsonString=[[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://test/json/json_data.php"]];
id response = [jsonParser objectWithString:jsonString error:NULL];
NSDictionary *feed = (NSDictionary *)response;
list = (NSArray *)[feed valueForKey:#"fname"];
the above code properly displays the value from fname but what do i do if i want to add lname to it. for eg, my object is
[{"fname":"Bill","lname":"Jones"},{"fname":"John","lname":"Jacobs"}]
i want to display names as Bill Jones, John Jacobs and so on in the list. Currently it only displays Bill, John..I tried doing something like #"fname"#lname but it wont work..Can anybody please help me..

An observation: the response from the JSON parser is not a dictionary, but an array given the string you pass in. Your code works because -valueForKey: is something an array will respond to. The array sends -valueforKey: to each element and builds an array out of the responses.
There are two ways you can do what you want (at least)
Iterate through the array explicitly
NSMutableArray* list = [[NSMutableArray alloc] init];
for (id anObject in response)
{
[list addObject: [NSString stringWithFormat: #"%# %#",
[anObject objectForKey: #"fName"],
[anObject objectForKey: #"lname"]]];
}
Add a category to NSDictionary
#interface NSDictionary(FullName)
-(NSString*) fullName;
#end
#implementation NSDictionary(FullName)
-(NSString*) fullName
{
return [NSString stringWithFormat: #"%# %#",
[self objectForKey: #"fName"],
[self objectForKey: #"lname"]];
}
#end
Then your existing code changes to
list = (NSArray *)[feed valueForKey:#"fullName"];

Related

Pick out certain part of NSMutableAray

How would I pick out certain part of NSMutableArray?
One fielding array from server is 2012-09-01 09:00:00 America/Los_Angeles
I am trying to get just the time.
I was thinking turning it into a string and then getting it and then back into NSMutablearray to populate to tableview cells.
I am still looking at documentation
Options I am thinking of:
-subarrayWithRange:
componentsSeparatedByString:
UPDATE:
Here is what I am doing now to get the field of appointments
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSDictionary* myslots =[json objectForKey:#"slots"];
self.timesArray = [[NSMutableArray alloc] init];
NSLog(#"allslots: %#", myslots);
for (NSString *slotKey in myslots.allKeys) {
NSDictionary *slot = [myslots valueForKey:slotKey];
for (myDays in slot){
if ([[self.myDays objectForKey:#"isReservable"] isEqualToNumber:[NSNumber numberWithInt:1]])
[self.timesArray addObject:[self.myDays objectForKey:#"begin"]];
//NSLog(#"This is the times count: %#", timesArray.count);
}
}
NSLog(#"These are the times avail: %#", self.timesArray);
[self.tableView reloadData];
}
All I want eventually is an array of just the times. I am sorry if I am not being clear. I am trying to. Please let me know what information I can provide to paint a clearer picture
I'd save it as a string first
NSString *someString = [myArray objectAtIndex:index];
and then use something like NSMakeRange to get just that bit
[someString substringWithRange:NSMakeRange(11,18)];

working with json data

I have the follow code that parses JSON data received from a server:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSArray *array_webdata=[[NSArray array] init];
NSString *searchStatus = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
array_webdata = [parsedata objectWithString:searchStatus error:nil];
NSDictionary *usersList = [array_webdata valueForKey:#"results"];
//I think that is not a real NSDictionary because if I write NSArray *keys = [usersList allKeys]; the execution crashes
NSLog(#"\n usersList =\n %# \n", usersList);
[searchStatus release];
[connection release];
[webData release];
[pool drain];}
the json data stored in usersList has the structure:
(
{
createTime = "date hour";
fullname = "user name";
"prof_id" = number;
thumb = "image.jpg";
},
{
data of rest of users...
}
)
And I would like create a class to store the data of each user and use "prof_id" when I want to use a particular use.
I need this because the app needs a list with all users (not tableview) and I think this is de easiest way.
Can someone help me? Thanks!!
Please used JsonKit Framework to parse json data received from web service.
Read data and parse using JSONKit:
NSData* jsonData = [NSData dataWithData:webData];
JSONDecoder* decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray* json = [decoder objectWithData:jsonData];
After that, you'll have to iterate over the json variable using a for loop.
Create new class with the name User (file->new->file) inherited from NSObject class, create required parameters in .h/.m file.(do synthesize to generate getter/setter for attributes)
import User.h in your connection class and create objects of User entity in iterator loop and add those object in global scope array.
for(NSDictionary *userInfo in json) {
User* user=[[User alloc] init];
user.fullName=[userInfo valueForKey:#"fullname"];
user.prof_id=[[userInfo valueForKey:#"prof_id"] integerValue];
// Add into your global array
[usersList addObject:user];
[user release];// if ARC is not enable
}
// Check for successful object creation
NSLog(#"USER LIST contain User class Objects- %#",userList);
if i'm not wrong the only thing you need to do is :
NSMutableArray *yourArray = usersList;
and then with a for loop like
for(int i = 0;i<[usersList count] ;i++)
{
NSMutableDictionary *yourDictionary = [usersList objectAtIndex:i];
int prof_id = [yourDictionary valueForKey:#"prof_id"];
}
you can get your prof_id like that.
i hope this helps...
Use JSON Framework, and parse data using below code.
NSString* newStr = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"yout link to json file"] encoding:NSUTF8StringEncoding error:nil];
NSLog(#"new str - %#",newStr);
NSArray *response = [newStr JSONValue];
NSLog(#"json array - %#",response);
Use the response array to show your results.

help on sorting NSMutableDictionary strings that are URL images

i want to populate the tablecell with title and imageurl from xml list.
i manage to store the title (NSMutableDictonary *sections )and imageURL (NSMutableDictonary *sectionsImg) into 2 NSMutableDictionary respectively.
/*******This is in viewDidLoad***/
Directory *allDirectory = [appDelegate.directories objectAtIndex:0];
for (allDirectory in appDelegate.directories)
{
NSDictionary *dica = [NSDictionary dictionaryWithObject:allDirectory.dirTitle forKey:#"dirTitle"];
NSDictionary *dico = [NSDictionary dictionaryWithObject:allDirectory.imageURL forKey:#"imageURL"];
[dirName addObject:dica];
[dirImage addObject:dico];
//NSLog(#"dic of items : %#",dirImage);
}
for (allDirectory in appDelegate.directories)
{
//retrieve the first letter from every directory title (dirTitle)
NSString * c = [allDirectory.dirTitle substringToIndex:3];
NSString * m = allDirectory.imageURL;
found = NO;
find = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}
for (NSString *stra in [self.sectionsImg allKeys])
{
if([stra isEqualToString:m])
{
find = YES;
}
}
if (!found)
{
[self.sections setValue:[[NSMutableArray alloc]init] forKey:c ];
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
if (!find)
{
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
}
for (NSDictionary *directory in dirName)
{
[[self.sections objectForKey:[[directory objectForKey:#"dirTitle"] substringToIndex:3]] addObject:directory];
//NSLog(#"hehehe have : %#",sections);
}
for (NSDictionary *directoryImg in dirImage)
{
//[[self.sectionsImg objectForKey:[[directoryImg objectForKey:#"imageURL"] substringFromIndex:0]] addObject:directoryImg];
[[self.sectionsImg objectForKey:[directoryImg objectForKey:#"imageURL"]] addObject:directoryImg];
//NSLog(#"HOHOHO have : %#",sectionsImg);
}
And on cellForRowAtIndexPath i declare a dictionary
NSDictionary *dictionary = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [dictionary objectForKey:#"dirTitle"];
but when i tried to declare a dictionary for imageURL
NSDictionary *dictionaryImg = [[self.sectionsImg valueForKey:[[[self.sectionsImg allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
it gives me a error :
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
any idea why? the logic is supposed to be the same where xml title and url can be retrieve and be displayed. Title is retrievable but imageURL is not. Help is deeply appreciated !
You are trying to sort an array... except for the fact your array isn't an array, but a NSDictionary.
Your code isn't the best at the moment. Your getting the idea of Dictionaries wrong and may be confusing them with arrays, so my best guess is your quite new to programming into objective-c.
You have two lists of things, if I'm not mistaken. The first list is the list of names, and the second list is an image corresponding with that name.
Below I'm going to do two things:
Firstly, I'm giving you two ways on how to fix your problem. It has a sample code included and gives you a small explanation with it. The possibility exist you don't understand parts of what I describe. In that case, you should;
Check out the link I described below the two solutions. It has a tutorial which makes you understand everything about arrays, dictionaries, tables and, as a bonus, XML-parsing.
So, in my opinion, you can do two things:
The first one is using an array of NSDictionaries. You'd be using a code which looks like:
NSMutableDictionary *itemOne = [[NSMutableDictionary alloc] init];
NSMutableDictionary *itemTwo = [[NSMutableDictionary alloc] init];
NSMutableArray *listOfAll = [[NSmutableArray alloc] init];
NSString *itemOneName = [[NSString alloc] initWithFormat:#"This is picture 1"];
NSString *itemTwoName = [[NSString alloc] initWithFormat:#"This is picture 2"];
NSData *imageOneData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic1.jpg"]];
NSData *imageTwoData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic2.jpg"]];
UIImage *itemOneImage = [UIImage imageWithData: imageOneData];
UIImage *itemTwoImage = [UIImage imageWithData: imageTwoData];
[itemOne setObject:itemOneNameString forKey:#"Name"];
[itemOne setObject:itemOneImage forKey:#"Image"];
[itemTwo setObject:itemTwoNameString forKey:#"Name"];
[itemTwo setObject:itemTwoImage forKey:#"Image"];
[listOfAll addObject:itemOne];
[listOfAll addObject:itemTwo];
Anything can be filled using that array. Just use something with a for-loop to iterate through your array.
for (int i = 0; i < [listOfAll count]; i++)
{
NSMutableDictionary *currentItem = [[NSMutableDictionary alloc] initWithDictionary:[listOfAll objectAtIndex:i]];
//Do something with that current item
}
You can also use that index in your tableView. In that case, you have to use your variable section instead of i to get your desired index.
The second one is using two arrays. Imagine you get an image named imageOne with the text imageName. Then you should use:
NSMutableArray *nameList = [[NSMutableArray alloc] init];
[nameList addObject: imageName];
NSMutableArray *imageList = [[NSMutableArray alloc] init];
[imageList addObject: imageOne];
If you want to use a certain item out of those lists, you just have to use the same indexnumber.
For example:
[theTitleLabel setText:[[NSString alloc] initWithFormat:#"%#", [nameList objectAtIndex:x]]];
[theImageView setImage:[imageList objectAtIndex:x]];
Make sure the x's are the same number.
I understand this is all a lot of information, especially if you're new to Objective - C. A tutorial exists which gives you a lot of information about how to use arrays, dictionaries and table views. As a bonus, you get to know a little about XML-parsing.
I suggest you walk through that tutorial and do everything and read everything it says. This should give you a nice start into the world of programming in iPhones.
Good luck!

How to dissect and reorganize info in an NSDictionary

So I have an array of NSDictionaries, each NSDictionary has a bunch of key/value pairs pertaining to aspects of a photo (from Flickr).
I'm making an app that has a UITableViewController whose cells should be each of the different categories of the photos. So in pseudocode, I'm trying to construct a new NSDictionary (with keys being categories of photos, values being the NSDictionaries of the photos that contains that key). I'm iterating through each NSDictionary in the initial array, getting the category tags, and saying, if my new NSDict doesn't contain this key, make a new key to an empty array. Then add the current NSDict to that array. I'm getting consistent errors, not sure why.
Here's the diluted code.
photoList = [FlickrFetcher photosWithTags:[NSArray arrayWithObjects: #"CS193p_SPoT", nil]];
NSLog(#"%#", photoList);
categories = [[NSDictionary alloc] init];
NSArray *temp = [[NSArray alloc] init];
for (id obj in photoList) {
temp = [[obj objectForKey:#"tags"] componentsSeparatedByString:#" "];
for (id string in temp) {
if (![categories objectForKey:string]) {
NSMutableArray *arr = [[NSMutableArray alloc] init];
[categories setObject:arr forKey:string];
//[arr release];
}
NSMutableArray *photos = [categories objectForKey:string];
[photos addObject:obj];
[categories setObject:photos forKey:string];
}
}
Thanks!
NSDictionary doesn't have a method setObject:forKey:. You need an NSMutableDictionary.
self.categories = [NSMutableDictionary dictionary];
Other than that, please do use Joost's excellent rewrite of your code.
SIGABRT, just so you know, most likely means that an assertion somewhere failed. In this case, it may be an assertion all the way down in CoreFoundation*; CF checks for mutability when you try to access a dictionary like that and causes an interrupt if the object isn't mutable.
*I have just learned about the CF source's availability recently and have been looking through it, so this may be just "new thing" bias and incorrect.
I don't notice any errors (syntax-errors, that is) in your code, however here is an updated piece of code which has been implemented a bit cleaner (and without memory leaks)
self.photoList = [FlickrFetcher photosWithTags:[NSArray arrayWithObjects: #"CS193p_SPoT", nil]];
NSLog(#"%#", photoList);
self.categories = [NSDictionary dictionary];
for (NSDictionary *obj in photoList) {
NSArray *temp = [[obj objectForKey:#"tags"] componentsSeparatedByString:#" "];
for (NSString *string in temp) {
NSMutableArray *photos = [categories objectForKey:string];
if (!photos) {
photos = [NSMutableArray array];
[categories setObject:photos forKey:string];
}
[photos addObject:obj];
}
}
If it's not working please tell us the exact warning, and were it is caused.

How to extract the actual NSString from json object as NSArray

I'm working with a large set of json and really just need the NSString representation of what's inside the NSArray -including all the { }
My question is this - is their a better way than simply looping through each NSArray inside the main NSArray and outputting the description one by one?
ie- the below is a start to this process but it's very brittle meaning I need to know each item inside the hat {} and this isn't something I actually care about. I just need the json string to move forward.
The working code is below (thank you in advance!)
NSString* responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSArray* json = [responseString JSONValue];
NSArray* item = [json valueForKeyPath:#"d.data"];
NSArray* hatjson = [item objectForKey:#"hat"];
NSMutableString * result = [[NSMutableString alloc] init];
for (NSObject * obj in hatjson)
{
[result appendString:[obj description]];
}
NSLog(#"the hat json is .. %#", result);
// …
NSArray* hatjson = [item objectForKey:#"hat"];
NSString *result = [hatjson JSONRepresentation];
NSLog(#"the hat json is .. %#", result);
I’m assuming you’re using SBJSON for JSON parsing. SBJSON defines a category on NSObject that includes the method
- (NSString *)JSONRepresentation;
This method returns a string with the JSON representation of a given object so long as the object is an instance of a class which SBJSON can convert to JSON (e.g. strings, numbers, arrays, dictionaries).
I'm assuming you're using the JSON library from here: https://github.com/stig/json-framework
You're complaining that the code you provided is brittle, but it sounds like, for what you want, the situation is brittle, so I think it's ok for the code that access it to be brittle, as long as you put NSAsserts in there so that you know ASAP when your assumptions have been broken.
I think the most brittle aspect of the code you've shown is that it assumes you're getting back NSArrays, when it appears from how you're accessing it that it's actually giving you NSDictionaries.
For instance, reading your code, I conclude that the responseString represents a JSON nested map looking something like this:
{ "d": { "data": { "hat": "baseball cap" } } }
The question then is "do you ever expect the value corresponding to the "hat" key to ever have more than one value?" I would genericize this code like so:
NSString* responseString = [[[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding] autorelease];
[responseData release];
id json = [responseString JSONValue];
id hatJSONValue = [json valueForKeyPath:#"d.data.hat"];
NSString* result = nil;
if ([hatJSONValue isKindOfClass: [NSArray class]] && [hatJSONValue count] == 1)
{
result = [[hatJSONValue lastObject] description];
}
else
{
NSAssert(NO, #"Assumptions about returned JSON were wrong.");
}
NSLog(#"the hat json is .. %#", result);
Generally speaking, you always have to make tradeoffs between writing non-brittle code and getting things done. The key should be that if your code is going to make assumptions, you should assert that they're true, so if the situation ever changes, you'll know!