Problem: Multiple selection tableview cells being reused - iphone

I have a tableview, i need to have a checkmark displayed everytime i select a row. (Multiple selection) My code is given below. I am also able to unselect a row.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *RootViewControllerCell = #"RootViewControllerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell];
if(nil == cell)
{
cell = [[[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:[NSString stringWithFormat:#"HelveticaNeue-Bold"] size:12];
textView.textColor = [UIColor colorWithRed:0.281 green:0.731 blue:0.8789 alpha:1];
cell.textLabel.text = [optionsArray objectAtIndex:[indexPath row]];
if (pathIndex == indexPath)
{
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
pathIndex = indexPath;
[surveytableView reloadData];
}
But i have a problem with the cells being reused. When i select a cell another cell elsewhere also gets selected. Only the checkmark (or no checkmark) is getting reused other details like the row title, etc., don't get reused. Any solutions to fix this. Thanks in advance.

Add it to cellForRowAtIndexPath:
if ([tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (![tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Worked for me

At your
if (pathIndex == indexPath)
you're comparing pointers not the values of them, try
[pathIndex isEqual:indexPath]
or use
- (NSComparisonResult)compare:(NSIndexPath *)otherObject;
Next you're assigning a value to pathIndex without retaining or copying it like
pathIndex = [indexPath copy];
(of course now since you're retaining the value, before copying your new object you have to release the previous one [pathIndex release];)
Finally, no multiple selection is provided by your implementation, only single selection. You could try adding and removing NSIndexPath objects to an NSMutableArray and check against their presence in your mutable array at cellForRowAtIndexPath instead.

The issue is that you only do something with the accessory if the current row matches pathIndex.... so what if it is a normal cell...? You never set it back. You want...
cell.accessoryType = UITableViewCellAccessoryNone;
if ([pathIndex isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
It is good practice to reset the cells before you set any specific properties.

Related

How to get accessoryType for UItableViewCell?

Please check the below code..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[contact_table reloadData];
}
As per the above code, I have checked all the table I am clicking, What should I do to uncheck again, I know I should change accessory type to None, but when, how do I know previously it was checked? Is there any API which tell us the accessary type of cell.
I have done in other table view by adding an extra member in my modal obj to track the checked and unchecked cell, however I just want to know is there any way without that?
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
tableView is a Data Presenter view object
TableView is just used to 'display' data, it is not the manager or tracker of data. You need to track the attributes of data in the backend. I mean if you want to keep track of which all rows are checked or unchecked, it cannot be managed by TableView, you need to take care of it either by using NSArray or any other object type.
Try below code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}

UITableView moves cell contents around when scrolling

I have seen other questions on here related to this, but I have their solutions in place, and things still move around when I scroll.
Basically, I have a table of data and I want the first and only the first row to have a UITableViewCellAccessoryDisclosureIndicator. The problem is, when I scroll around, the indicator duplicates, deletes, and moves to other cells. Here is my code..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(indexPath.row == 0) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [tabledata objectAtIndex:indexPath.row];
return cell;
}
The problem is something with the indexPath.row variable.. its somehow returning 0 in other cells that aren't the very first (when it comes to displaying cells). HOWEVER... the data is always right from my array(which implies the value HAS to be correct) and in my
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
method, i only wish to change screens when row 0 is clicked.. and regardless of where I have scrolled to, no cells trigger except the very first. So it seems THAT check is always correct while the one inside cellForRowAtIndexPath is not...
Most likely, you are re-using cells that already have the accessoryType set. You need to explicitly set it to NOT show on cells where it shouldn't.
if(indexPath.row == 0){
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}

How to track the index of all seleted cells in UITableView

I have a UITableView with about 20 rows. I also use check mark accessory to identify the selected. The problem I face now is that the selection gets messed up when I scroll (here I am selecting multiple rows). So after scroll the selected checkmark has vanished. Can anyone help me to find a way? in didSelectRowAtIndexPath:
NSMutableDictionary *rowDict = [tableList objectAtIndex:[indexPath row]];
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
else
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
checkedIndexPath = indexPath;
NSLog(#"the checked psths are :%#",checkedIndexPath);
}
And in cellforrowatIndexpath I use
if([self.checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
But this works only for single selection. What should I do for multiple selection?
You can have an NSMutableArray which can add n number of NSIndexPaths corresponding to the cells selected. When a cell is deselected, you can remove that indexpath from the array.
You should use an array to store checked indices. If you use a single property then only the last selected row will get the correct accessoryType.
I used this code many times (With some minor changes as required)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView
accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
{
//add your own code to set the cell accesory type.
return UITableViewCellAccessoryNone;
}

iPhone Coding: Problem with UITableView selection

I have a strange problem with my UITableView. I want all the cells in the table to be selectable, such that if a cell is selected, an appropriate action is executed. All the cells in my table are currently selectable apart from the cell at row 0 (the cell at that appears at the top of the table). This cell is not selectable, even though it has been set to allow for selection. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
tableView.allowsSelection = YES;
static NSString *SettingsTableID = #"SettingsTableID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SettingsTableID];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier: SettingsTableID] autorelease];
}
cell.textLabel.text = [tableHeadingsArray objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Many thanks.
Sorry everyone, I'm being stupid. :) This code was in my ViewController sub-class. I copied the class from an example, and forgot to check it over thoroughly before using it.
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSUInteger row = [indexPath row];
if (row == 0)
return nil;
return indexPath;
}
Deleting this has fixed the problem.
Cheers.

UITableView Checklist Problem

I have this bizarre problem. I'm making a checklist program with XCode and I'm using UITableView with UITableViewCellAccessoryCheckmark. I can select cells and the checkmark will appear, but somehow, other cells that I have NOT yet selected below will also have a checkmark appear. Any ideas?
Here's my check mark coding:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
cell = [aTableView cellForRowAtIndexPath: indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I don't know if this affects it, but I also implemented this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
if(tableView == Table1){
switch(indexPath.section){
case 0:
cell.textLabel.text = [array1 objectAtIndex:indexPath.row];
break;
case 1:
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
break;
case 2:
cell.textLabel.text = [array3 objectAtIndex:indexPath.row];
break;
}
//cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
}
if(tableView == Table2){
cell.textLabel.text = [array4 objectAtIndex:indexPath.row];
}
return cell;
}
Thanks.
Set the cell.accessoryType each time you call tableView:cellForRowAtIndexPath:. Otherwise, when you reuse a cell, you'll get it's accessoryView instead of what you're expecting.
So, yeah, you'll need to keep track in when NSIndexPaths are selected by some method other than just looking at the accessoryType.
You should keep the checked/unchecked info in data source (array).
I also advise you to remove the cell.accessoryType = UITableViewCellAccessoryNone; line.
This line will be executed only for few first cells. All the other cells will be "reused" - meaning that the old (already initiated) cells will be used, and you will have to modify the details that are displayed on these cells (all inside cellForRowAtIndexPath as you do now).
In addition you will have to add a similar line (something like cell.accessoryType = ([[array objectAtIndex:indexPath.row] boolValue] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;).
In general, I suggest you to use one array for holding the data for your table, when each item in the array will be a dictionary. This way you will be able to hold the texts and the boolean checkmarks (inside NSNumber) and easily access them when needed.