date wise sorted uitableview - iphone

I am developing an iPhone application .
In the application I want to show the uitableview data sorted on the date field :
Suppose I have a Person object with fields name,birthdate,phone number etc.
Now I have array of Person and I am sorting that array on date field.
Now I am not understanding that how to handle these two methods ;
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
i.e
How to count date wise objects and determine ?

Assuming you have one section and a sorted NSArray or NSMutableArray called _personArray:
- (NSInteger) numberOfSectionsInTableView:(UITableView *)_tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)_tableView numberOfRowsInSection:(NSInteger)_section {
return [_personArray count];
}
- (UITableViewCell *) tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)_indexPath {
Person *_person = [_personArray objectAtIndex:_indexPath.row];
NSString *_cellIdentifier = [NSString stringWithFormat: #"%d:%d", _indexPath.section, _indexPath.row];
UITableViewCell *_cell = [_tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
if (_cell == nil) {
_cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:_cellIdentifier] autorelease];
}
_cell.textLabel.text = _person.name;
_cell.detailTextLabel.text = _person.birthdate;
return _cell;
}
If you require multiple sections, split your array into multiple NSMutableArray instances, each containing Person instances associated with a specific section.
Then modify -numberOfSectionsInTableView: to return the number of sections (a count of the number of section arrays), as well as the other two methods to: 1) get element counts within a section array and; 2) to recall the right Person for a given indexPath.section and indexPath.row.

Related

UITableView with two types of cells

UITableView contains, suppose, 50 rows. The first row contains one item and every even row index cell contains two items?
for that we need to use two XIB view for each alternate row?
What would be the logic for totalrowcount and cellAtRowatindexpath logic?
Is there any other option?
I imagine your table looks like this:
+---------------------+
| Data 1 | --> Cell Type 1
+---------------------+
| Data 2 | Data 3 | --> Cell Type 2
+---------------------+
| Data 4 |
+---------------------+
| Data 5 | Data 6 |
+---------------------+
. ... .
First of all, you should design two different UITableViewCell nibs for those cell types. Personally, I would use Storyboard, design two dynamic cells with different identifiers and call them when needed. For example:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"Cell Type 1"];
Let's get to tableView's data source methods. I assume that the data is stored in an array called self.tableData. You can build a logic to return the number of rows as follows:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return ceil([self.tableData count]*(2.0f/3.0f));
}
And then in your cellForRowAtIndexPath method, return these cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
NSUInteger objectIndex = floor(indexPath.row*(3.0f/2.0f));
if (indexPath.row % 2 == 0) {
// define cell as Cell Type 1 from nib
cell.yourLabel.text = [self.tableData objectAtIndex:objectIndex];
} else {
// define cell as Cell Type 2 from nib
cell.yourLabel1.text = [self.tableData objectAtIndex:objectIndex];
cell.yourLabel2.text = [self.tableData objectAtIndex:(objectIndex+1)];
}
return cell;
}
Note that, I am assuming your tableData array contains something like NSString objects and you have UILabel's on your cells. The above code fetches the objects from your data source from the corresponding indices and populates your labels.
totalrowcount stands 50
cellForRowAtIndexpath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// make 2 cellidentifiers here and use it for different nib
UITableViewCell *cell;
if(indexpath.row==0){
//load first nib
}
else
{
//load second nib
}
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row % 2 == 0) {
//cell type 1
} else if(indexPath.row % 2 == 1) {
//cell type 2
}
}
Above code will help you assign alternate cell pattern
If you have 2 types of cells I suggest use 2 different identifiers and when you dequeue the cells you get the cell need.
Firstly use - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
and pass 1 section here as :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
and then
In - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method you will pass total number of rows as a datasource to the tableview.
Ex: if you have to display 50 rows then pass 50 rows as :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 50;
}
And in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
you will pass the cell as per the need
Ex:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row %2 ==0)
{
// First alternaate cell which you need to display at even index
return ALTERNATE_NIB_1;
}
else
{
// Second alternaate cell which you need to display at odd index
return ALTERNATE_NIB_1;
}
return nil;
}
Hope it helps you.

Adding dynamic sub-rows by selecting tableview row in tableview iPhone errors?

I want to add row dynamically. I have tableview list of building names. If some one choose building(didSelectRowAtIndexPath) then respective floors of building should get added dynamically as subrow. Its like maximizing and minimizing the subrow on respective building list selection. How do I do this. Thanks in advance...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// There is only one section.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of time zone names.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return [indoorZones count];
}
}
cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == indoortable || tableView == indoortable_iPad)
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray; //cell bg
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell.
//cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
cell.textLabel.text =[indoorZones objectAtIndex: indexPath.row];
//[cell setIndentationLevel:[[self.indoorZones objectAtIndex:indexPath.row] intValue]];
return cell;
}
}
didSlectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
zonesFloor = [[NSMutableArray alloc]init];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
[zonesFloor addObject:zonesFloorA];
if (tableView == indoortable )
{
NSUInteger i=indexPath.row+1;
for (NSArray *count in self.indoorZones) //app is crashing here giving error.......Collection <__NSArrayM: 0x4b1d550> was mutated while being enumerated.
{
[zonesFloor addObject:[NSIndexPath indexPathForRow:i inSection:0]];
[self.indoorZones insertObject:zonesFloor atIndex:i++];
}
[[self indoortable] beginUpdates];
[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView deselectRowAtIndexPath:selectedIndexPath animated:NO];
}
It Gives following error [__NSArrayI compare:]: Or [NSIndexPath _fastCStringContents:]: unrecognized selector sent to instance. I tried many ways but may be I am lacking somewhere. Please suggest. thanks in advance.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSIndexPath *selectedIndexPath = [self.indoortable indexPathForSelectedRow];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
if (tableView == indoortable )
{
for (NSString *str in zonesFloorA) {
[indoorZones addObject:str];
}
//[[self indoortable] beginUpdates];
//[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
//[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView reloadData];
}
may this meet your requirement
Okay, so not to sound mean, but there are almost too many issues here to count.
Let's start with a basic explanation of how tableView's work so that you can start to fix this:
First, the tableView asks how many sections are in the table by calling:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
}
In your code, you simply tell it that it has one section. However, in your later code, when you try to add rows to your table, you tell it that you want to add your rows to a second section (with an index of 1). Therefore, you either need to add these rows to section 0 instead, or update the above method to tell it that, sometimes, there are two sections.
Second, the tableView asks how many rows are in each section of the table by calling:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
}
In your code, you are simply returning the number of zones. However, like above, you need to include the rows that you have added to your table. If you are adding them to a different section, then you need to return different values, depending on how many rows are in the section with the index asked for in the section variable. If they are all in the same section, then you need to add them up and return the correct value.
Third, the tableView asks for an actual cell for the row by calling:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
}
In your code, you are only returning a cell which has data populated by the indoorZones array, but you also need to supply cells which are configured properly for the specific zone/floor. Again, you either need to determine this by section number or row number as appropriate.
Finally, when you click on a row, the tableview tells you by calling the following method:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
In this method, you need to update your data source that is used by the previous functions so that when they get called again, they will provide the correct data. Your data source must mirror the way that you want your table view to look. In your case, you have an array called indoorZones. This is good if you just want to display a list of zones, which is what you start off doing. However, when you want to add more rows, you need to add more rows to your data source first, so that when the tableView starts this process over, it is already there.
If you want everything to stay in one section, then I would come up with a data source that can include both types of rows, and be able to distinguish between them so that cellForRowAtIndexPath can create the proper type of cell and return it.
If you want two sections, then I would add a second array for the second section (since it is not the same type of data) and return the appropriate values in each of these methods, based on which array you need to use for that section.
I hope this helps!

Load UITableView with NSArray

I have an NSArray of NSDictionaries where each dictionary has the same keys. I want a section for each dictionary in the array.
For example, if the array has 4 dictionaries, then the table will have 4 sections. Then each cell in each section will correspond with that value in the dictionary.
Is there an easy way to do this?
For example, I have an NSArray with 3 Dictionaries where each dictionary has 3 keys, name, gender, and date.
This means that the table should have 3 sections, where each section title is the date key for its dictionary. Then there are 2 cells for that section corresponding to the name and gender values.
Ya I'm familar with those methods, but I'm not sure how to get the
date key from the dictionary correctly setup in the
titleForHeaderInSection method.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return (NSString *)[myArray objectAtIndex:section] objectForKey:#"date"];
}
This worked flawlessly. But how can I edit the code in cellForRowAtIndexPath in a similar manner?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
/* Create myCell UITableViewCell */
NSString *value = #"Unknown";
if (indexPath.row == 0){
value = (NSString *)[[myArray objectAtIndex:indexPath.section] objectForKey:"name"];
}else if (indexPath.row == 1){
value = (NSString *)[[myArray objectAtIndex:indexPath.section] objectForKey:#"gender"];
}
myCell.textPropertyOrWhatever = value;
return myCell;
}
Are you even trying this at all? :P

Howto? In TableView, if NSMutableArray is empty, show other Array

In a tableview I'm displaying local soccer matches from an NSMutableArray that are planned for this week. If there are no matches, I want to display a cell saying something like: 'No matches this week'. I think I have to call for another array, or probably dictionary, if the NSMutableArray of matches is empty, but at this point I have no idea where to start. Any thoughts on how to achieve this?
First, test if there are matches. If there are, tell the tableView there are as many rows as matches. If there aren't, return 1 row.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [matches count] ? [matches count] : 1;
}
Then, when creating your cell, check if there are matches, if there are, show the appropriate one, if there aren't, show "No Matches".
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// boiler plate cellForRowAtIndexPath stuff here...
NSUInteger row = [indexPath row];
cell.textLabel.text = [matches count] ? [matches objectAtIndex:row] : #"No Matches";
return cell;
}
Both of the answers given are fine, but depending on what you do with the table you may hit some problems later on - for example, if you insert or delete the first row in the table (i.e. adding the first match, or deleting the last match) then you will have an exception raised because the number of rows in the section hasn't changed, but you have added or deleted a row.
You also may need to prevent deletion etc of the special row. It can all get a bit messy.
If this is an issue you may find it better to have the "No matches" message displayed in a header or footer view, which you toggle the visibility of appropriately.
in your table's tableView:numberOfRowsInSection: delegate method, you'll need to know if there are any matches. If not, return 1. This will guarantee you one row in your table.
Then, in your tableView:cellForRowAtIndexPath: delegate method, if there are no matches, you return a cell with the text "No Matches", otherwise, you return a cell according to the match:
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
BOOL hasMatches = [myMatchesArray count] > 0;
return hasMatches ? [myMatchesArray count] : 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL hasMatches = [myMatchesArray count] > 0;
UITableViewCell *cell = .....
if (hasMatches) {
MyMatchObject *match = (MyMatchObject *)[myMatchesArray objectAtIndex:indexPath.row];
[cell.textLabel setText:match.matchText];
}else{
[cell.textLabel setText:#"No Matches"];
}
return cell;
}

how to control the index displayed on the tableview

I am able to show a index on the right side similar to songs view on the ipod. During searching the index bar gets minimized automatically. And when i go back to my actual table view the index size is small and it displays only few alphabets. How to stop the resizing of this ?
you have to place proper delegate methods of UITableView in your viewController.m file.
for example I have placed following code.
Please read comments carefully.
#pragma mark -
#pragma mark Table view data source
// an array count which has values for index - like A,B,C etc.
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//return [NSArray arrayWithArray:keys];
return [keys count];
}
// an array which has values for index - like A,B,C etc.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
return keys;
}
// return how many number of rows are required for each section.
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[dMain valueForKey:[keys objectAtIndex:section]] count];
}
// return title of section
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [keys objectAtIndex:section];
}
// create each row for different sections
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"%i %i",indexPath.row,indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.font=[UIFont fontWithName:#"Helvetica" size:12];
//cell.textLabel.text=[[[objects objectAtIndex:indexPath.row] valueForKey:#"marketname"] stringByReplacingOccurrencesOfString:#"_and_" withString:#"&"];
cell.textLabel.text=[[[[dMain valueForKey:[keys objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"marketname"] stringByReplacingOccurrencesOfString:#"_and_" withString:#"&"];
}
return cell;
}