iPhone SDK: How To Create Sections On UITableView - iphone

I have this data that I need to put inside my UITableView but I'm getting confused on how to properly implement it. I cannot properly separate the values to segregate the Boys data to the Girls data.
{
"QUERY": {
"COLUMNS": [
"NAME",
"GENDER"
],
"DATA": [
[
"Anne",
"Girl"
],
[
"Alex",
"Boy"
],
[
"Vince",
"Boy"
],
[
"Jack",
"Boy"
],
[
"Shiela",
"Girl"
],
[
"Stacy",
"Girl"
]
]
},
"TOTALROWCOUNT": 6
}
I have this codes:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [genderArray count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [genderArray objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [namesArray count];
}
namesArray has all the values returned by NAME while genderArray has all the values of GENDER. I'm getting confused.

AS you are getting confused, break your data into pieces. You want two arrays, one per section. So you want one array of boys names, and another array of girls names.
You can obtain this by iterating through the embedded DATA array.
Turn your data into an NSDictionary object. Your data looks like JSON so...
NSDictionary* myDict = [NSJSONSerialization JSONObjectWithData:myJsonData
options:0 error:&error];
Extract the data...
NSArray* dataArray = [myDict objectForKey:#"DATA"];
Iterate...
NSMutableArray* boys = [[NSMutableArray alloc] init];
NSMutableArray* girls = [[NSMutableArray alloc] init];
for (id person in dataArray) {
if ([[person objectAtIndex:1] isEqualToString:#"Girl"])
[girls addObject:[person objectAtIndex:0]];
else [boys addObject:[person objectAtIndex:0]];
}
Now you have two arrays, one for each of your table sections. Make an array of sections, and put these arrays into it:
NSArray* sections = [NSArray arrayWithObjects:boys,girls,nil];
Make a separate array for your section headers:
NSArray* headers = [NSArray arrayWithObjects:#"Boys",#"Girls",nil];
Now your data source methods look like this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sections count];
}
- (NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section
{
return [headers objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [[sections objectAtIndex:section] count];
}
and finally
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
...
cell.textLabel.text = (NSString*)[[self.sections objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row];

Related

How to get display data in UITableView Section tables with single Array

I have data on a server which I want to show in the a tableView.
The problem is that I want to show data based on categories so I have array categories which has categories which will be section titles and inside them there data so for display the data in section I have to declare Array.
e.g. If there are three categories then we have to make three array to populate data but what if there are more categories as categories are dynamic and come from server.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [categoryArray count] ;
}
And how to set title for section title, as it is in category array, so if it is section one by one in array.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSLog(#"Number of Sections");
if(section == 0)
return #"Sales";
if(section == 1)
return #"Soft Skills";
}
How to show data in tableView cells may I create arrays for all the categories?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0)
{
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
int count=[resultArray count];
NSLog(#"resultArry Row Counts is %d",count);
return [resultArray count];
}
else{
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
int count=[resultArrayOne count];
NSLog(#"resultArry Row Counts is %d",count);
return [resultArrayOne count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Table Cell Data");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (indexPath.section==0) {
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
ObjectData *theCellData = [resultArray objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.sub_Category;
cell.font=[UIFont fontWithName:#"Helvetical Bold" size:14];
NSLog(#"Cell Values %#",cellValue);
cell.textLabel.text = cellValue;
return cell;
}
else {
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
ObjectData *theCellData = [resultArrayOne objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.sub_Category;
cell.font=[UIFont fontWithName:#"Helvetical Bold" size:14];
NSLog(#"Cell Values %#",cellValue);
cell.textLabel.text = cellValue;
return cell;
}
}
Since getting the categories from the server does not seem to be your question I base my answer on pre filled arrays for a better visualization.
NSMutableArray *categories = #[#"Cat1", #"Cat2"];
// creata a dictionary with all the array for the categorie rows
NSMutableDictionary *rowDict = #{#"Cat1":#[#"Cat1Row1",#"Cat1Row2",#"..."],
#"Cat2":#[#"Cat2Row1", #"Cat2Row2",#"..."]
Key to this solution is that you use the category string as key for the dictionary.
You can now access the title like this
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return categories[section];
}
And access your rows like this
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// ...
// create or deque a cell like you normally would do
// now configure the cell
cell.textLable.text = [rowDict[categories[indexPath.section]] objectAtIndex:indexPath.row]
}
use
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [categoryArray objectAtindex:section];
}
for section title.
likewise, store the values for each categories in a nsmutable array NSDictionary and display the data for each category in uitableviewcell.
Try the below code. It'll solve your problem :
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [categoryArray objectAtIndex:section];
}
EDIT :
First Create a model data class to store data of your categories.
Use this model class to feel your numberOfRowsInSection and cellForRowAtIndexPath delegate function.
Instead of creating different-different array for each category. Store this array in one model class. It'll be easy to handle.

How to set numberOfSectionsInTableView, titleForHeaderInSection using dynamic json data

I have some json data given below and I want to display it in a table where the section headers are Departments, Designing, Employees, Developing, Employees.
I used static data in numberOfSectionsInTableView, titleForHeaderInSection but I want to do it using dynamic data.
How can I do this?
{
"Departments":[
{
"name":"Designing",
"id":"1.1",
"Employees":[
{
"name":"Ramesh",
"id":"1.1.1",
"salary":"4lakhs"
},
{
"name":"Suresh",
"id":"1.1.2",
"salary":"4lakhs"
}
]
},
{
"name":"Developing",
"id":"1.2",
"Employees":[
{
"name":"Ram",
"id":"1.2.1",
"salary":"4lakhs"
},
{
"name":"Sam",
"id":"1.2.2",
"salary":"4lakhs"
}
]
}
}
first you have to create a NSDictionary from the string JSON object you specified.
NSDictionary *myDict = [NSJSONSerialization JSONObjectWithData:webData options:nil error:NULL];
Then in the table view delegate methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[myDict valueForKey:#"Departments"] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[[myDict valueForKey:#"Departments"] objectAtIndex:section] valueForKey:#"Employees"] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[myDict valueForKey:#"Departments"] objectAtIndex:section] valueForKey:#"name"];
}
Or at least I would try to set them like this.

Sorting NSDictionary from JSON for UITableView

I am having trouble trying to sort my NSDictionary in order, and it's been weeks and I still haven't figured it out, so I wish some one could give me a hand here...
NSDictionary data is from JSON and the data is already sorted from the server and it displayed in order in the JSON, but when it retrieved and converted to NSDicitionary, the order is all wrong...
This is the JSON
{
"categories":{
"unknownCategoryName":[
{ "key1":"value1",
"key2":"value2"
}],
"unknownCategoryName1":[
{ "key1":"value1",
"key2":"value2"
}],
"unknownCategoryName2":[
{ "key1":"value1",
"key2":"value2"
}],
"unknownCategoryName3":[
{ "key1":"value1",
"key2":"value2"
}]
}
}
The category quantity and its name will not be known until the JSON is received, so this is what I am using to get the count and setting up the tableView and the section
NSDictionary *results = [jsonString JSONValue];
NSDictionary *all = [results objectForKey:#"categories"];
self.datasource = all;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.datasource count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = [[self.datasource allKeys] objectAtIndex:section];
return title;
}
And what I want to do is to list out the section and the section title as the order in the JSON.... rather than a chaos display like
unknownCategory3
unknownCategory1
unknownCategory
unknownCategory2
The "unknownCategory" is Product Category name, they are not in alphabet order, without any number, and they are already sorted and display in order in the JSON...
So, it would be great if you guys could help.
Thanks in advance...
Keys are not ordered in NSDictionaries, so you have to sort the keys first before using them in your table view. So, instead of using [self.datasource allKeys] to get your section titles, first create a sorted array: sorted = [[self.datasource allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)], and then use that array to get the titles: title = [sorted objectAtIndex:section].
After Edit to answer a further question:
To use the sorted array to get the values you want into your table, I think this should be close. You would have to add a property, NSArray *sorted, to your .h file, and then this in your .m (this is assuming the structure of your json is as you posted above):
NSDictionary *results = [jsonString JSONValue];
NSDictionary *all = [results objectForKey:#"categories"];
self.datasource = all;
self.sorted = [[self.datasource allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.sorted count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = [self.sorted objectAtIndex:section];
return title;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.datasource valueForKey:[self.sorted objectAtIndex:section]]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
NSArray *theArray = [self.datasource valueForKey:[self.sorted objectAtIndex:indexPath.section]];
NSString *text1 = [[theArray objectAtIndex:0] valueForKey:#"key1"];
NSString *text2 = [[theArray objectAtIndex:0] valueForKey:#"key2"];
cell.textLabel.text = [NSString stringWithFormat:#"%#\r%#",text1,text2];
cell.textLabel.numberOfLines=0; // this set the number of lines to unlimited
return cell;
}
You didn't say how you wanted to display two different values in one table row -- in this example, I concatenated them into one string with a return between the two.
Seems a strange JSON. You could have used like this
{
"categories": [
"unknownCategoryName": [
{
"key1": "value1",
"key2": "value2"
}
],
"unknownCategoryName2": [
{
"key1": "value1",
"key2": "value2"
}
]
]
}
And it is very easy to sort if you did like above.
To sort JSON provided in your question
-(NSMutableArray *)getAllKeys:(NSDictionary *)jsonDictionary{
NSDictionary *all = [results objectForKey:#"categories"];
NSMutableArray *allKeys = [all allKeys];
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject: sorter];
[allKeys sortUsingDescriptors:sortDescriptors];
[sorter release];
return allkeys;
}
-(void)createSortedDictionary{
NSMutableDictionary *dictionaryMutable=[NSMutableDictionary dictionary];
for(NSString *string in allkeys){
[dictionaryMutable setObject:[all objectForKey:string] forKey:string];
}
}
dictionaryMutable will hold the sorted dictionary
Did you write this JSON or are you getting it from somewhere that you can't edit? It looks malformed to me. categories should be an array and the current array placement makes no sense. If the JSON looked like this:
{
categories:[
{unknownCategoryName:
{ key1:value1,
key2:value2
}},
{unknownCategoryName2:
{ key1:value1,
key2:value2
}}
]
}
Then you could read categories into an NSArray, and your delegate methods would look like this (and display in proper order):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [categoriesArray count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSDictionary *dict = [categoriesArray objectAtIndex:section];
NSString *title = [[dict allKeys] objectAtIndex:0];
return title;
}
I think the only way you can preserve the original order is to do the initial parsing yourself after creating a JSON string from the JSON data. If the structure of the JSON string is as you posted, you could use an NSScanner to find the strings between quote marks, and then select only the ones that have a [ after the final quotation mark to add to an array which will be your ordered array of keys. You can then create the NSDictionary using a JSON parser, and get the values by looping through your ordered keys and sending them valueForKey:.

Allocating Right Amount of Rows Based On Array

I have a NSMutableArray filled with NSMutableArray's. I would like to fill my table view up with the appropriate amount of rows, based on the size of a particular indexes array.
I currently have the array setup to grab the first element in the array, and the table then sets the amount of rows to that particular array's size. Ideally, i'd like to set the rows to the count of each element, of which most (arrays) have differing sizes.
Here is what I currently have:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
NSMutableArray *blah = [[workoutManager workouts] objectAtIndex:0];
return [blah count];
}
Any help would be greatly appreciated.
Do it in following way:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
return [[workoutManager workouts] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
NSMutableArray *blah = [[workoutManager workouts] objectAtIndex:indexPath.section];
return [blah count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
NSMutableArray *blah = [[workoutManager workouts] objectAtIndex:indexPath.section];
YourObj *obj = [blah objectAtIndex:indexPath.row];
//Do further...
}

Filling UITableView Cells from an NSMutableArray within a NSMutableDictionary

I have a NSMutableDictionary that contains NSMutableArrays. The dictionary represents divisions, and the arrays represents the departments within that division. I am trying to fill in the cells of a UITableView from the contents of the NSMutableArray. I currently have the UITableView displaying the correct amount of sections (divisions) and the correct number of cells within each division [departmentArray count];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [divisionArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSArray *temp = [divisionDict objectForKey:[divisionArray objectAtIndex:section]];
return [temp count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *temp = [divisionArray objectAtIndex:section];
if ([temp isEqualToString:#"School of Humanities and Social Sciences"])
{
temp = #"Humanities and Social Sciences";
} else if ([temp isEqualToString:#"School of Science and Mathematics"]) {
temp = #"Science and Mathematics";
} else if ([temp isEqualToString:#"School of Education"]) {
temp = #"Education";
}
return temp;
}
I have tried many different things in cellForRowAtIndexPath to display the names of the departments for each division, but I cannot get it to work. I understand I have to get the array for each key, then go through that array and get the names of each dept, but implementing that in cellForRowAtIndexPath is confusing me.
Any help would be greatly appreciated!
I think you would be better off changing your structure to have an NSMutableArray that contains NSMutableDictionarys that contain NSMutableArrays for the rows and NSStrings for the titles. This I found to be very convenient in some of the code I have been developing.
Here is how is works:
You have an NSMutableArray that has an entry for each division, that ends up being a section in the table view.
Within each entry of the array you have an NSMutableDictionary that contains a two entries, one that I used the key #"rows" for, that contains an array with the rows, and one that I used the key #"title" for, that holds the section header.
Your code then becomes:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [divisionArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSArray *rowsInSection = [[divisionArray getObjectAtIndex: section] objectForKey: #"rows"];
return [rowsInSection count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *rawTitle = [[divisionArray getObjectAtIndex: section] objectForKey: #"title"];
NSString *sectionTitle = [rawTitle stringByReplacingOccurrencesOfString: #"School of " withString: #""];
return sectionTitle;
}
Keeping my structure the same, I was able to figure it out, heres the lines I places in my cellForRowAtIndexPath method:
NSArray *temp = [divisionDict objectForKey:[divisionArray objectAtIndex:[indexPath section]]];
[[cell textLabel] setText:[temp objectAtIndex:[indexPath row]]];