Logic for UITableViewCellAccessoryCheckmark - iphone

I want to make a typical situation: when user selects any cell, it's accessoryType turns in checkmark. Only one cell's accessoryType can be checkmark. And then I wanna save in NSUserDefaults indexPath.row so my app will be able to know which cell user selected and make some changes in options. So I wrote this wrong code:
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// checkedIndexPath is NSIndexPath
if(self.checkedIndexPath)
{
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self.checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedIndexPath = indexPath;
[[NSUserDefaults standardUserDefaults]setObject:[NSNumber numberWithInt:self.checkedIndexPath.row]forKey:#"indexpathrow" ];
}
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Part of code from cellForRowAtIndexPath
if(indexPath.row == [[[NSUserDefaults standardUserDefaults]objectForKey:#"indexpathrow"]intValue ])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
However, this code works badly. When you open the UITableView, there is an already selected cell in the table and when you press another there are two checkmarked cells...How can I improve my code or should I change it whole ? Any suggestions ?
Thanks !

Try this code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// checkedIndexPath is NSIndexPath
NSIndexPath *previousSelection = self.checkedIndexPath;
NSArray *array = nil;
if (nil != previousSelection) {
array = [NSArray arrayWithObjects:previousSelection, indexPath, nil];
} else {
array = [NSArray arrayWithObject:indexPath];
}
self.checkedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:array withRowAnimation: UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Part of code from cellForRowAtIndexPath
NSString *cellID = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
[cell autorelease];
}
// some code for initializing cell content
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if(self.checkedIndexPath != nil && indexPath.row == self.checkedIndexPath.row)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}

Related

How to maintain state of selection of row in table view?

i am a beginner in xcode. I am creating a questionnaire type list with multiple rows in scroll. But when I select a row and scroll it doesn't retains its state and when I come back, it also loses its selection. So anyone please kindly let me know how to achieve that,i have tried something like this,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(val==1)
{
checkedArr=[[NSMutableArray alloc] init];
for (int i = 0; i<17; i++)
{
[checkedArr addObject:#"1"];
}
NSLog(#"Checked arr size %i",[checkedArr count]);
return 17;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%i",indexPath.row];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil)
{
cell= [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:14.0];
}
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:18.0];
UIView *selectionColor = [[UIView alloc] init];
selectionColor.backgroundColor = [UIColor colorWithRed:99/255.0f green:209/255.0f blue:248/255.0f alpha:1.0];
cell.selectedBackgroundView = selectionColor;
if([[checkedArr objectAtIndex:indexPath.row] isEqual:#"0"])
{
cell.accessoryView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]];
NSLog(#"checkedArr 0000000");
}
else if ([[checkedArr objectAtIndex:indexPath.row] isEqual:#"1"])
{
cell.accessoryView=nil;
NSLog(#"checkedArr 111111");
}
cell.textLabel.frame=CGRectMake(75.0, 50.0, 150.0, 20.0);
cell.textLabel.text=[listArray objectAtIndex:indexPath.row];
NSLog(#"Checked arr size %i",[checkedArr count]);
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
cell=[questionTable cellForRowAtIndexPath:indexPath];
[checkedArr replaceObjectAtIndex:indexPath.row withObject:#"0"];
if([[checkedArr objectAtIndex:indexPath.row] isEqual:#"0"])
{
cell.accessoryView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]];
NSLog(#"checkedArr 0000000");
}
else if ([[checkedArr objectAtIndex:indexPath.row] isEqual:#"1"])
{[questionTable deselectRowAtIndexPath:indexPath animated:YES];
cell.accessoryView=nil;
NSLog(#"checkedArr 111111");
}
NSLog(#"Val is %i",val);
NSLog(#"selected is %#",[listArray objectAtIndex:indexPath.row]);
// NSLog(#"Checked arr descripton %#",[checkedArr description]);
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryView = UITableViewCellAccessoryNone;
}
In my application i used same code for check mark as accessoryType,check this.
take it in .h file mutable array arSelectedRows;
- (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];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
//Do anything you want for cell here
if([arSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arSelectedRows addObject:indexPath];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[arSelectedRows removeObject:indexPath];
}
NSLog(#"arSelectedRows are :%#",arSelectedRows);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
EDIT
//if you want only single check mark
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arSelectedRows removeAllObjects];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arSelectedRows addObject:indexPath];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[arSelectedRows removeObject:indexPath];
}
NSLog(#"arSelectedRows are:%#",arSelectedRows);
[self.tableview reloadData];//Reload your tableview here
}
it will help you.
First your cellForRowAtIndexPath method create new cell each time whenever you scroll up/down tableView, it is very bad for memory management.
Just remove [questionTable deselectRowAtIndexPath:indexPath animated:YES] in your cellForRowAtIndexPath method
I think you need to use this api below:-
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
If you are using dynamic cells, and updating your row with some kind of class variable like a NSArray, you might have set your variable to weak instead of strong.

Multiple accessory checkmarks displayed on a UITableView

I have a UITableView that displays checkmarks when a row is selected. The problem is that when the table view scrolls multiple checkmarks are shown when only one was ever row selected. The problem arises as the table scrolls and the dequeue process occurs. Here's my cellForRowAtIndexPath: method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:204.0/255.0 green:56.0/255.0 blue:55.0/255.0 alpha:1];
}
// Get item from tableData
NSDictionary *item = (NSDictionary *)[displayItems objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"key"];
[cell.textLabel setFont:[UIFont fontWithName: #"Asap-Bold" size: 14.0f]];
return cell;
}
and didSelect method:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
selectedCityTableString = cell.textLabel.text;
cellAccessoryImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon-tick.png"]] ;
cellAccessoryNoneImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#""]] ;
if (cell.accessoryType==UITableViewCellAccessoryNone)
{
// cell.accessoryType=UITableViewCellAccessoryCheckmark;
cell.accessoryView = cellAccessoryImageView;
if (prev!=indexPath.row) {
cell=[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:prev inSection:0]];
//cell.accessoryType=UITableViewCellAccessoryNone;
cell.accessoryView = cellAccessoryNoneImageView;
prev=indexPath.row;
}
}
else{
// cell.accessoryType=UITableViewCellAccessoryNone;
cell.accessoryView = cellAccessoryNoneImageView;
}
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *mutCityStr = [[selectedCityTableString stringByReplacingOccurrencesOfString:#" " withString:#"+"] lowercaseString];
// NSString *mutCityStr = #"c";
[prefs setObject:mutCityStr forKey:#"selectedCityTableString"];
[prefs synchronize];
#ifdef DEBUG
NSLog(#"mutCityStr is %#",mutCityStr);
NSLog(#"selectedCityTableString is %#",selectedCityTableString);
NSLog(#"posting notification from TWO TABLES");
#endif
[[NSNotificationCenter defaultCenter] postNotificationName:#"TTSelectedList" object:selectedCountryTableString];
}
Supposing you have a property (attribute) called selectedRow use the combination of this methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if (indexPath.row == self.selectedRow) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// If there is a cell selected deselect
if (self.selectedRow != NSNotFound) {
NSIndexPath *previousIndexPath = [NSIndexPath indexPathForRow:self.selectedAQIType inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:previousIndexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Select the touched cell
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.selectedRow = indexPath.row;
}
In your .h file
int selectedRow;
In your .m file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// your other code for cell init,etc
int row = [indexPath row];
cell.accessoryType = (row == selectedRow) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
cell.textLabel.textColor= (row == selectedRow) ? [UIColor colorWithRed:242.0f/255.0f green:104.0f/255.0f blue:42.0f/255.0f alpha:1] : [UIColor blackColor] ;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedRow = [indexPath row];
[tableView reloadData];
}
Hope this helps!!!
UITableView's delegate method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath reuses the cell based on the reuseidentifier. Hence you need to reset the entire cell contents to default.
In your case uncheck the cell's view before you return the cell.
To solve this problem, store your selected row indexes in one NSArray. (in didSelectRowAtIndexPath method)
And in cellForRowAtIndexPath method, check whether indexPath.row is available in that array then enable your checkmark, else disable.
Note: Maintain array for check-uncheck event
Hope this will help you.

deselect the previously selected cell in tableview

I have Table View with Multiple sections in it.
I want to allow only one row selected...My tableview's Selection Property is Set to:SingleSelectioin
Now I am doing this to set the checkmark for selected row
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
else
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
Now what I want is that when I select any other cell, the previously selected cell should be set back to unselected.
I have tried with this
lastIndexpath=indexPath;
and then
[tableView deselectRowAtIndexPath:lastIndexpath animated:YES];
but it gives me bad access on lasIndexPath
EXC_BAD_ACCESS (code=1,address= 0xfe000008)
Kindly Help me with this
any New Suggestions are also welcomed
You want to mark your selected cell, then in didSelectRowAtIndexPath you can write code like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
cell = (UITableViewCell*)[tableView cellForRowAtIndexPath:previousSelectedIndexPath];
[cell setAccessoryType: UITableViewCellAccessoryNone];
if(previousSelectedIndexPath!=nil)
{
[previousSelectedIndexPath release];
previousSelectedIndexPath = nil;
}
previousSelectedIndexPath = [indexPath retain];
}
where previousSelectedIndexPath is previously selected index;
Declare NSIndexPath *lastIndexpath in .h of your controller:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if( lastIndexpath){
if([tableView cellForRowAtIndexPath:lastIndexpath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:lastIndexpath].accessoryType = UITableViewCellAccessoryNone;
}
else
{
[tableView cellForRowAtIndexPath:lastIndexpath].accessoryType = UITableViewCellAccessoryCheckmark;
}}
lastIndexpath=[indexPath retain]
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
else
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
}
//Take a variable of type indexpath in .h
NSIndexPath *myIndexPath
//Now check it in your cellForRowAtIndexPath: delegate method ..
if(indexPath == myIndexPath)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
//and in your didSelect: Delegate method ...
[tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark
myIndexPath = indexPath;
[tableView reloadData];
Hope this will help you.
in delegate method willSelectRowAtIndexPath , get the current selected index path, set accerroryType to none.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *currentSelectedIndexPath = [tableView indexPathForSelectedRow];
[tableView cellForRowAtIndexPath:currentSelectedIndexPath].accessoryType = UITableViewCellAccessoryNone;
if ([indexPath isEqualTo: currentSelectedIndexPath])
{
return nil;
}
return indexPath;
}

Checkmarks in a UITableView

I create a tableview with 20 cells.
And when I select first row, it will show checkmark on it.
But when I scroll tableview, then it not only one checkmark on tableview cell.
It also show on another cell.
What's the problem with this?
self.dataAry = [NSArray arrayWithObjects:#"0",#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",#"11",#"12",#"13",#"14",#"15",#"16",#"17",#"18",#"19",nil];
marks = [NSMutableArray new];
for (int i = 0 ; i < [self.dataAry count]; i++) {
[marks addObject:#"NO"];
}
- (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];
}
cell.textLabel.text = [dataAry objectAtIndex:indexPath.row];
if ([[marks objectAtIndex:indexPath.row] isEqualToString:#"YES"]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
// Configure the cell.
return cell;}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark){
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone];
[selectArray removeObject:[self.dataAry objectAtIndex:indexPath.row]];
[marks replaceObjectAtIndex:indexPath.row withObject:#"NO"];
}
else {
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
[selectArray addObject:[self.dataAry objectAtIndex:indexPath.row]];
[marks replaceObjectAtIndex:indexPath.row withObject:#"YES"];
}
}
I think it is due to reusing the checkmarked cell. To correct that, write this:
*if ([[marks objectAtIndex:indexPath.row] isEqualToString:#"YES"]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else {
[cell setAccessoryType:UITableViewCellAccessoryNone];*
Out of cell reusing space. That is After:
...
}
//Configure the cell.
just before
*return cell;*
Try this. Here selectedRow is an integer .Assign selectedRow = -1 in viewDidLoad.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
int row = [indexPath row];
cell.accessoryType = (row == selectedRow) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedRow = [indexPath row];
[tableView reloadData];
}
check this
- (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;
}
i faced same issue. for me, solution was adding a single line of code.
cell.accessoryType = UITableViewCellAccessoryNone;
adding the above code after:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
this solution may not be useful for coder who posted the question, but may help new folks like me who face same issue as raised by the original quesiton.

UITableView, having problems changing accessory when selected

I'm using a UITableView to allow selection of one (of many) items. Similar to the UI when selecting a ringtone, I want the selected item to be checked, and the others not. I would like to have the cell selected when touched, then animated back to the normal color (again, like the ringtone selection UI).
A UIViewController subclass is my table's delegate and datasource (not UITableViewController, because I also have a toolbar in there).
I'm setting the accessoryType of the cells in cellForRowAtIndexPath:, and updating my model when cells are selected in didSelectRowAtIndexPath:. The only way I can think of to set the selected cell to checkmark (and clear the previous one) is to call [tableView reloadData] in didSelectRowAtIndexPath:. However, when I do this, the animating of the cell deselection is weird (a white box appears where the cell's label should be). If I don't call reloadData, of course, the accessoryType won't change, so the checkmarks won't appear.
I suppose I could turn the animation off, but that seems lame. I also toyed with getting and altering the cells in didSelectRowAtIndexPath:, but that's a big pain.
Any ideas? Abbreviated code follows...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* aCell = [tableView dequeueReusableCellWithIdentifier:kImageCell];
if( aCell == nil ) {
aCell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:kImageCell];
}
aCell.text = [imageNames objectAtIndex:[indexPath row]];
if( [indexPath row] == selectedImage ) {
aCell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
aCell.accessoryType = UITableViewCellAccessoryNone;
}
return aCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
selectedImage = [indexPath row]
[tableView reloadData];
}
I solved it like hatfinch suggested in his edit. My code sample make sure there's only one row checked but I'm sure you can tweak it if thats not what you need.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int newRow = [indexPath row];
int oldRow = [lastIndexPath row];
if (newRow != oldRow)
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:
indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:
lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
lastIndexPath = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I had this exact same problem and never solved it.
In the end it was moot for me because I had to listen for changes in the model (the selection could change outwith the user's control if a connection was lost) so I just changed the model and let the notification reload the data, but it didn't look too pretty (it was like a non-animated deselection, but one run loop iteration late!)
I suspect the only way to do it is, as you suggest, keeping a cache of references to the cells themselves. This shouldn't be too messy if you write a UITableViewCell subclass to encapsulate the logic, overriding -prepareForReuse.
Still, not pretty, and if the ringtone guys at Apple had to do it this way, they ought to have pressed the UITableView team harder to fix it!
EDIT:
Well, what do you know?! This is really easy after all. -[UITableView cellForRowAtIndexPath] will give you the actual cells (or nil if they're offscreen) and you can just change the accessoryType.
I have a cleaner way of doing it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
I'm using this simple and nice working mechanism with reloadRowsAtIndexPaths.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *rowsArray = [NSArray arrayWithObjects:indexPath, selectedIndexPath, nil];
self.selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:rowsArray withRowAnimation:UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
.... skipped usual code .....
if ([selectedIndexPath compare:indexPath] == NSOrderedSame) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
This will work as desired...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int newRow = [indexPath row];
int oldRow = [lastIndexPath row];
if (newRow == oldRow){
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
lastIndexPath = indexPath;
}
if (newRow != oldRow)
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
lastIndexPath = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:index];
oldCell.accessoryType = UITableViewCellAccessoryNone;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
index = indexPath;
}