Advice on creating table with dynamic data in IOS - ios

I am trying to create a table with dynamic data and I'm kind of stuck. Here is how my data is structured :
NSMutableArray *bigArray;
bigArray has many NSDictionary items.
each items has only one entry.
sectionName is the key, NSMutableArray is the value.
There are many objects in the value NSMutableArray.
I tried to explain this as simple as I could, here is the part where I'm stuck.
//easy
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [bigArray count];
}
//medium
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[[[bigArray objectAtIndex:section] allValues] objectAtIndex:0] count];
}
I can't figure out this part how to implement this method based on my current data structure :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"MyCell"];
MyObject *obj = //Need this part
cell.textLabel.text = obj.name;
return cell;
}
Simply put, I'm trying to insert dynamic sections with dynamic data. I'm looking for advice from more experienced developers, how would you tackle this?

Assuming I understood well how your data is structured, here's how I would do it:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
//this will get you the dictionary for the section being filled
NSDictionary *item = [bigArray objectAtIndex:indexPath.section];
// then the array of object for the section
NSMutableArray *mutableArray = [item objectForKey:#"sectionName"];
//you then take the object for the row
MyObject *obj = [mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = obj.name;
return cell;
}
Don't forget to set the reuse identifier for the cell prototype in the attributes inspector

Related

How to generate Table View Sections Dynamically and group similar values in that particular section?

So mi requirement is i have dataset like this
car - toyota
car
white
car - BMW
car
blue
car - Jaguar
car
brown
Bike - KTM
Bike
orange
Bike - Honda
Bike
black
like this i have n number of objects.
i need to generate o/p as following.
section names
car,bike...
inside car section i need toyota, BMW,Jaguar
inside Bike section i need KTM,Hond.
how can i achieve this
Note: I need to create sections and datas dynamically based on the data set
If any one know the solution kindly help me thanks in advance
the codes that i have used
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return sectionData.count;
//section data has only sections e.g. car,bike.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [sectionData objectAtIndex:section];
}
- (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];
}
NSManagedObject *carobj = [StoredDataForDisplay objectAtIndex:indexPath.row];
if ([[carobj valueForKey:#"type"] isEqualToString:[sectionData objectAtIndex:indexPath.section]] ) {
cell.textLabel.text = [carobj valueForKey:#"name"];
}
return cell;
}
You just need to update the tableview datasource before showing these data. For example, you can create a NSDictionary with group names("car", "bike" etc) as the key, a NSArray as the value, so the value for key "car" will be an array of "toyota", "BMW", "Jaguar" objects.
You can then create a NSArray to hold all the group names in the order you need. groupArray = dataDictionary.allKeys;
Then you can display all group names and all items under this group:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return groupArray.count;
//section data has only sections e.g. car,bike.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[dataDictionary objectForKey:groupArray[section]] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [groupArray objectAtIndex:section];
}
- (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];
}
NSManagedObject *carobj = [[dataDictionary objectForKey:groupArray[indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [carobj valueForKey:#"name"];
return cell;
}
You need call reloadData in table view when you change your data set. Your dataSourceDelegate look good, but in method numberOfRowsInSection need return valid rows number, rows number need get from your data set. And you can use for data storing nsdictionary + nsarray for fast access to data.

iOS - Simple Table Sections with Array Data

I'm just starting with iOS/Xcode and have been Googling/Youtubing for an hour and can't find a matching tutorial. All I'm trying to do right now is display a table with a list of exercises (rows) that are grouped by bodypart (sections). The bodypart sections will never change, but the user will be able to add a custom exercise to a bodypart.
Now, I'm assuming that I need an array for the sections and also an array for exercises...creating those is simple enough. I'm running into a problem assigning exercises to specific sections. Here's an example of the faulty code that when rendered, displays both exercises under both sections...also there aren't any section names being generated in the table so I'm not sure where that comes into play either.
Here's a screenshot of the result (as a side note, not sure why my nav controller isn't rendering): http://i.imgur.com/icoJgEq.jpg
Create the individual items:
#property NSString *exerciseName;
#property NSString *exerciseCategoryName;
Create/Allocate the arrays:
#property NSMutableArray *exerciseCategories;
#property NSMutableArray *exercises;
self.exerciseCategories = [[NSMutableArray alloc]init];
self.exercises = [[NSMutableArray alloc]init];
Fill the arrays with some default data:
- (void)loadInitialData {
FNTExerciseCategories *category1 = [[FNTExerciseCategories alloc]init];
category1.exerciseCategoryName = #"Chest";
[self.exerciseCategories addObject:category1];
FNTExerciseCategories *category2 = [[FNTExerciseCategories alloc]init];
category2.exerciseCategoryName = #"Biceps";
[self.exerciseCategories addObject:category2];
FNTExercises *exercise1 = [[FNTExercises alloc]init];
exercise1.exerciseName = #"Bench Press";
[self.exercises addObject:exercise1];
FNTExercises *exercise2 = [[FNTExercises alloc]init];
exercise2.exerciseName = #"Barbell Curl";
[self.exercises addObject:exercise2];
}
Load the data:
[self loadInitialData];
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.exerciseCategories count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.exercises count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
MFTExercises *exercise = [self.exercises objectAtIndex:indexPath.row];
cell.textLabel.text = exercise.exerciseName;
return cell;
}
Thank you very much to anybody that can chime in!
Actually in tableView:numberOfRowsInSection: you are returning the count of the entire exercises array. So with your sample data you would have two rows per section. Try making an array of exercises for every section and then code something like the following:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0) {
return [self.chestExercises count];
}
else if (section == 1) {
return [self.bicepsExercises count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
MFTExercises *exercise;
if (indexPath.section == 0) {
exercise = [self.chestExercises objectAtIndex:indexPath.row];
}
else if (indexPath.section == 1) {
exercise = [self.bicepsExercises objectAtIndex:indexPath.row];
}
cell.textLabel.text = exercise.exerciseName;
return cell;
}
In this case the chestExercises array would only contain the "Bench Press"-exercise and the bicepsExercises would only contain the "Barbell Curl"-exercise. So you would get one row per section.
For achieving that the sections have titles you would need to implement the method
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section {
return [self.exerciseCategories objectAtIndex:section];
}
which gives the sections the title according to the names stored in the array.
A more sophisticated way to build your datasource would be to create a NSDictionary with the section names as the keys (bodyparts) and the values being arrays containing the exercises for the bodypart. For instance if your categories are merely strings you could build such a dictionary with your sample data (for the purpose of demonstration I added another exercise):
FNTExerciseCategories *category1 = [[FNTExerciseCategories alloc]init];
category1.exerciseCategoryName = #"Chest";
[self.exerciseCategories addObject:category1];
FNTExerciseCategories *category2 = [[FNTExerciseCategories alloc]init];
category2.exerciseCategoryName = #"Biceps";
[self.exerciseCategories addObject:category2];
FNTExercises *exercise1 = [[FNTExercises alloc]init];
exercise1.exerciseName = #"Bench Press";
FNTExercises *exercise2 = [[FNTExercises alloc]init];
exercise2.exerciseName = #"Barbell Curl";
FNTExercises *exercise3 = [[FNTExercises alloc]init];
exercise3.exerciseName = #"Another Exercise";
// the instance variable self.exercises is a NSMutableDictionary now of course
self.exercises = [[NSMutableDictionary alloc] init];
exercises[category1.exerciseCategoryName] = #[exercise1];
exercises[category2.exerciseCategoryName] = #[exercise2, exercise3];
The advantage here is that you now have one dictionary containing all arrays that contains all your data. So as you're adding more data you don't have to change your implementation of the tableView datasource. BTW I am using Modern Objective-C syntax for the dictionary and arrays.
Having created a dictionary like that you could then simply implement your table view data source like so:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// This gives the name of the category at the current section.
// It is then used as a key for the dictionary.
NSString *currentCategory = [[self.exerciseCategories objectAtIndex:section] exerciseCategoryName];
return [self.exercises[currentCategory] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSString *currentCategory = [[self.exerciseCategories objectAtIndex:indexPath.section] exerciseCategoryName];
MFTExercises *exercise = [self.exercises[currentCategory] objectAtIndex:indexPath.row];
cell.textLabel.text = exercise.exerciseName;
return cell;
}
Using a NSDictionary may or may not benefit your app but you don't have to create an array as instance variable for every body part you have. It may also be more easy to save a single dictionary to disk for persistence.
First of all, you should practice it with WWDC UITableView section. There are many source code that uses UITableView, UICollectionView and UIScrollView.
What you need in that code is you need to return section header for exerciseCategories, you only defined number of section in - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView this delegate function but you are returning all nil value for the section header at the moment.
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
FNTExerciseCategories *category = [self.exerciseCategories objectAtIndex:section];
return category. exerciseCategoryName;
}
this will display your section. but you need to think about the structure of your data because right now you are not returning correct number for each section you are just returning [self.exercises count] for all section.
And to render the UINavigationController, you need to push the view rather than present view as modal.
[self.navigationController pushViewController:exerciseView animated:YES];

UITableview grouped style only showing one value from array?

MY UITableview Group style only showing one value from the array of 4 elements.
in viewdidload i add following array
_displayThemeItems=[[NSArray alloc]initWithObjects:#"Default",#"Night",#"Sepia" ,#"Blue" ,nil];
_displayThemeIcons=[[NSArray alloc]initWithObjects:[UIImage imageNamed:#"day.png"],[UIImage imageNamed:#"night.png"],[UIImage imageNamed:#"sepia.png"], [UIImage imageNamed:#"blue.png"],nil];
and my table delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_displayThemeItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// No cell available - create one.
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];}
NSLog(#"rray%#",_displayThemeItems);
cell.textLabel.text = [_displayThemeItems objectAtIndex:indexPath.row];
cell.imageView.image=[_displayThemeIcons objectAtIndex:indexPath.row];
return cell;
}
Your code look fine to me, the only the only reason that I can think amy effect the result you see is how you set up your table view.
Make sure that your table view frame is bug enough to show the 4 items, and make sure you set the tabe view data source.
Add the "}" just before the return such that the code where you set the title and image comes under the "if" statement.

Populate tableview from NSDictionary

I have an NSDictionary received from a json request that looks like this:
RESULT : (
{
Id1 = 138;
lat = "45.5292910";
long = "-73.6241500";
order = "2343YY3"
},
{
Id1 = 137;
lat = "45.5292910";
long = "-73.6241500";
order = "2343YY3"
}, etc.
I want to display it in a TableView (CellforRowAtIndexPath), so I obtain the data as NSArray. The method seems inefficient as each key Id1, lat, long, etc is created as an NSArray so that I can display them each with: [self.data1 objectAtIndex:indexPath.row]; [self.data2 objectAtIndex:indexPath.row], etc.
How can I achieve the same thing without creating and using 4 NSArrays? Can I use a single NSArray or the NSMutableDictionary which stores the data?
UPDATED:
When the TableView loads, it is initially empty but I have a button on that same VC that loads a modal view of a form. When I load the form and then dismiss it returning to the TableView, the data is LOADED! Could you suggest what I am missing?
Yes you can use a single array. The trick is to create an array with each array entry holding a dictionary. Then you query the array to populate your tableview.
E.g.: If your array is a property called tableData and you have custom tableview cell called CustomCell then your code might look something like the following:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.latitude.text = [[self.tableData objectAtIndex:indexPath.row] objectForKey: #"lat"];
cell.longitude.text = [[self.tableData objectAtIndex:indexPath.row] objectForKey:#"long"];
// continue configuration etc..
return cell;
}
Similarly, if you have multiple sections in your tableview then you will construct an array of arrays, with each sub-array containing the dictionaries for that section. The code to populate the tableview would look something similar to the following:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return [self.tableData count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [[self.tableData objectAtIndex:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.latitude.text = [[[self.tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey: #"lat"];
cell.longitude.text = [[[self.tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"long"];
// continue configuration etc..
return cell;
}
TL;DR; Take your dictionaries created from your JSON data and put them in an array. Then query the array to populate the tableview.
You can do as follows:
// main_data = Store your JSON array as "array of dictionaries"
Then in cellForRowAtIndexPath do as follows:
NSDictionary *obj = [main_data objectAtIndex: indexPath.row];
// Access values as follows:
[obj objectForKey: #"Id1"]
[obj objectForKey: #"lat"]
...
...

UITableView Indexing

I have an indexed table view that organizes cities in a state by their first letter. What I have working is an NSMutableDictionary is created with the keys of A,B,C,etc. and the corresponding cities are added to their respective arrays. ex:
Y = (
Yatesboro,
Yeagertown,
York,
"York Haven",
"York New Salem",
"York Springs",
Youngstown,
Youngsville,
Youngwood,
Yukon
);
Z = (
Zelienople,
Zieglerville,
"Zion Grove",
Zionhill,
Zionsville,
Zullinger
);
now, my table view loads with the correct number of sections, and rows within the sections and the indexing control works fine with this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [cities count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if([searchArray count]==0)
return #"";
return [searchArray objectAtIndex:section];
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[cities objectForKey:[searchArray objectAtIndex:section]] count];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
NSLog([NSString stringWithFormat:#"clicked index : %i",index]);
if (index == 0) {
[tableView scrollRectToVisible:[[tableView tableHeaderView] bounds] animated:NO];
return -1;
}
return index;
}
My issue is now populating the text of the table cell with the text for each section...Any thoughts on how I can grab this info?
the cellForRowAtIndexPath gets a parameter of type NSIndexPath passed which contains both the required row and section. See NSIndexPath UIKit Additions for more details.
With that being said, this might work in your particular case:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier] autorelease];
}
NSString *letter = [searchArray objectAtIndex:indexPath.section];
NSArray *city = [cities objectForKey:letter];
cell.text = [city objectAtIndex:indexPath.row];
return cell;
}
Not sure if I got it right (haven't tried on a compiler), but you may get the general idea by now :)

Resources