Expand and Collapse specific row after selected in UITableViewCell - objective-c

I am trying to implement the expand/collapse table view cell. It's working good for many rows; they can be expanded and collapsed after clicked.
But what happen is when my table view has only one row; when I click it and then all the rest of the rows are expended too even though they are empty.
Here my code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedIndex == indexPath.row){
return 100;
}else{
return 44;
}
}
// Display in cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"CommentTableCell";
//-- try to get a reusable cell --
CommentTableCell *cell = (CommentTableCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//-- create new cell if no reusable cell is available --
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
VocabularyController *vc;
// Display word from database else display vocabulary when searching
if (tableView != self.strongSearchDisplayController.searchResultsTableView) {
vc = [self.myArray objectAtIndex:indexPath.row];
}else{
vc = [self.filteredArray objectAtIndex:indexPath.row];
}
cell.nameLabel.text = vc.korean;
return cell;
}
// Selected Cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(selectedIndex == indexPath.row){
selectedIndex = -1;
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
NSArray* rowsToReload = [NSArray arrayWithObjects:rowToReload, nil];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
return;
}
if(selectedIndex >= 0){
NSIndexPath *previousPath = [NSIndexPath indexPathForRow:selectedIndex inSection:selectedSection];
selectedIndex = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade];
}
// Finally set the selected index to the new selection and reload it to expand
selectedIndex = indexPath.row;
[tableView beginUpdates];
[tableView endUpdates];
}
// I would like show my screen shot.
How to expand only selected row when there is only one result after search? How to keep the other empty stay the same !
Thank for reading.

I don't think you can change that behavior for a one row table -- the table shows the cell dividers based on the height of that one row. If you don't want this look, then I think you have to set the separatorStyle to UITableViewCellSeparatorStyleNone. You could make a custom cell that has a line at the bottom to mimic a cell separator if want to see a line only at the bottom of filled cells.

Related

Show and Hide a Custom Cell

My UITableView has one section, and if all cells are visible there will be a total of 6.
There is only one cell that I would like to be able to show and hide.
Here's an overview:
cell 0 - always shown
cell 1 - always shown
cell 2- always shown
cell 3 - always shown
cell 4 - initially hidden / will show or hide if cell 3 is tapped
cell 5 - always shown
Here's a sample of what I have tried for animating/showing the cell through didSelectRowAtIndexPath. Not sure if I am on the right track, but if someone could take a look and help me see where I have messed up I would greatly appreciate it!
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.row == 3)
{
if (self.indexPathSelected != indexPath)
{
[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:self.indexPathSelected.row+1 inSection:self.indexPathSelected.section]].hidden = YES;
[tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
[tableView beginUpdates];
[[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] performSelector:#selector(setHidden:) withObject:NO afterDelay:0.25];
self.indexPathSelected = indexPath;
[tableView endUpdates];
return;
}
}
}
So when I tap on cell 3, it just makes the last cell flicker.
By considering, there will be of total 6 rows in tableview and only one section, for this better u make a mutable array to hold all the objects for ur tableview then use insertRowsAtIndexPaths: withRowAnimation: and deleteRowsAtIndexPaths: withRowAnimation: instead of using selector following code gives the example how to hide and show the tableview cell
mutArray = [[NSMutableArray alloc]initWithObjects:#"cell 1",#"cell 2",#"cell 3",#"cell 4",#"cell 6", nil]; //initially ur array contains only 5 objects notice that "cell 5" is not there this will be hidden
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [mutArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.aTableView dequeueReusableCellWithIdentifier:#"cell"];
if(mutArray.count != 6) //initially only 5 rows are present
{
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [mutArray objectAtIndex:indexPath.row];
cell.textLabel.backgroundColor = [UIColor clearColor];
return cell;
}
else //for 5th row it must be a custom cell
{
return [mutArray objectAtIndex:indexPath.row];//becz u are already initilised ur custom cell just return it
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if(indexPath.row == 3)
{
int totalRows = [tableView numberOfRowsInSection:indexPath.section];
[tableView beginUpdates];
if(totalRows == 5)
{
//initilise ur custom cell and add it to datasource array
CustomCell *customCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"customCell"];
customCell.textLabel.text = #"cell 5";
[mutArray insertObject:customCell atIndex:4];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:indexPath.row + 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
}
else
{
[mutArray removeObjectAtIndex:5];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:indexPath.row + 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
}
[tableView endUpdates];
}
}
if all ur cells are custom then dont need to comepare in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
Hope this helps u :)

Why won't UITableViewCellAccessoryCheckMark Go Away?

Okay so I am slowly figuring this out. Just one more issue I am having. I am using a string and saying that if the string is equal to the cell text to put a checkmark on it when it loads the tableView.
Here is my code for that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ([cell.textLabel.text isEqualToString:transferData]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I am then telling it to remove that checkmark and add the checkmarks accordingly when being selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
cell.accessoryType = UITableViewCellAccessoryNone;
UITableViewCell *cellCheck = [tableView
cellForRowAtIndexPath:indexPath];
cellCheck.accessoryType = UITableViewCellAccessoryCheckmark;
transferData = cellCheck.textLabel.text;
NSLog(#"%#", transferData);
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:indexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
Everything works fine, except when it first loads. For some reason when I select on another cell, the checkmark that is originally loaded with the tableView won't go away. Why is this?
You are making a common mistake.
When selecting the cell, you are setting the state of the check mark directly. What you should be doing is setting the state of the checkmark in the data source and let the table cell configure itself from the data source.
Edited example for an exclusive checked table view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *changedIndexPaths = nil;
NSIndexPath *currentCheckedIndexPath = [self indexPathOfCurrentCheckedObject];
if (currentCheckedIndexPath && ![currentCheckedIndexPath isEqual:indexPath]) {
// There is currently a checked index path - unselect the data source and
// add it to the changed index array.
[[self.tableData objectAtIndex:currentCheckedIndexPath.row] setChecked:NO];
changedIndexPaths = #[indexPath, currentCheckedIndexPath];
} else{
changedIndexPaths = #[indexPath];
}
[[self.tableData objectAtIndex:indexPath.row] setChecked:YES];
[self.tableView reloadRowsAtIndexPaths:changedIndexPaths withRowAnimation:UITableViewRowAnimationNone];
}
I have a new sample app you can download to see the whole project:
You need:
if (self.selectedPath && [indexPath isEqual:self.selectedPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Cells get reused. If you conditionally set any cell attribute, you must always have the 'else' part to reset the attribute.
Edit: With the above change in your cellForRowAtIndexPath: method, do the following in your didSelectRowAtIndexPath: method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *oldSelection = self.selectedPath;
if (self.selectedPath) {
UITableViewCell* uncheckCell = [tableView cellForRowAtIndexPath:self.selectedPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
self.selectedPath = nil;
}
if (oldSelection == nil || ![indexPath isEqual:oldSelection]) {
UITableViewCell* checkCell = [tableView cellForRowAtIndexPath:indexPath];
checkCell.accessoryType = UITableViewCellAccessoryCheckmark;
self.selectedPath = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath];
}
And get rid of the didDeselectRowAtIndexPath: method.
And of course you need the selectedPath property of type NSIndexPath *.
This code lets you pick 0 or 1 row.

iOS - NSRangeException only when breakpoints are disabled

Recently started developing apps, so excuse my ignorance. I have a tableView, and when a cell in the table view is clicked, I want to insert a new row directly below it. This currently works in my code. However, I also want the row that has been inserted to be removed once the cell has been clicked again. This is giving me the NSRangeException saying I am out of bounds in my array.
I figured this probably has to do with my tableView delegate/data methods, so I set up break points at each of them. With the break points enabled, the cell is removed perfectly. However, when I disable the breakpoints, and let the application run on its own, it crashes. How could break points possibly be affecting this?
Here is the relevant code:
- (NSInteger) numberOfSectionsInTableView:(UITableView *)songTableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)songTableView
numberOfRowsInSection:(NSInteger)section{
bool debug = false;
if (debug) NSLog(#"--TableView: rankings");
if (expandedRow == -1)
return [self.songs count];
else //one row is expanded, so there is +1
return ([self.songs count]+1);
}
- (UITableViewCell *)tableView:(UITableView *)songTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
bool debug = false;
if (debug) NSLog(#"--tableView: tableView");
NSUInteger row = [indexPath row];
if (row == expandedRow){ //the expanded row, return the custom cell
UITableViewCell *temp = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"test"];
return temp;
}
UITableViewCell *cell = [tableViewCells objectAtIndex:row];
return cell;
}
}
- (NSString *)tableView:(UITableView *)songTableView
titleForHeaderInSection:(NSInteger)section{
//todo: call refresh title
return #"The Fresh List";
}
- (CGFloat)tableView:(UITableView *)songTableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44.0; //same as SongCell.xib
}
- (void)tableView: (UITableView *)songTableView
didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
bool debug = true;
//todo: if the user selects expanded cell, doesn't do anything
SongCell *cell = (SongCell *)[songTableView cellForRowAtIndexPath:indexPath];
if (cell->expanded == NO){
//change cell image
cell.bgImage.image = [UIImage imageNamed:#"tablecellbg_click.png"];
cell->expanded = YES;
//add new cell below
NSInteger atRow = [indexPath row] + 1;
NSIndexPath *insertAt = [NSIndexPath indexPathForRow:atRow inSection:0];
NSArray *rowArray = [[NSArray alloc] initWithObjects:insertAt, nil];
if (debug) NSLog(#"Expanded row: %d", atRow);
expandedRow = atRow;
[tableView insertRowsAtIndexPaths:rowArray withRowAnimation:UITableViewRowAnimationTop];
}else { //cell is already open, so close it
//change cell image
cell.bgImage.image = [UIImage imageNamed:#"tablecellbg.png"];
cell->expanded = NO;
NSIndexPath *removeAt = [NSIndexPath indexPathForRow:expandedRow inSection:0];
NSArray *rowArray = [[NSArray alloc] initWithObjects:removeAt, nil];
if(debug) NSLog(#"--about to delete row: %d", expandedRow);
expandedRow = -1;
[tableView deleteRowsAtIndexPaths:rowArray withRowAnimation:UITableViewRowAnimationTop];
//remove expaned cell below
}
}
This is just a guess, but it's a good idea to wrap code that changes the table structure in calls to
[tableView beginUpdates];
[tableView endUpdates];
I bet this returns null: [NSIndexPath indexPathForRow:expandedRow inSection:0]; and if it does it blows ...
hth
I hate to answer my own questions but I figured it out.
I was loading up my tableView from an array of objects. When I added the cell, that array still only held 30 objects, whereas my table held 31. I was correctly returning the numberOfRowsInSection method.
Here is the modification I made. Notice the extra else if:
NSUInteger row = [indexPath row];
if (row == expandedRow){ //the expanded row, return the custom cell
if(debug) NSLog(#"row == expandedRow");
UITableViewCell *temp = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"test"];
return temp;
}
else if (expandedRow != -1 && row > expandedRow)
row--;
My array of objects and the UITableViewCells were suppose to match up 1-1. After the expanded row, indexPath's row because off by 1. Here is my quick fix to this problem, although I'm sure there is a better way to solve this.

indexPathForSelectedRow always returns 0,0 irrespective of the row selected

I would like to replace the cell that is touched by a custom cell. I do this by calling reloadRowsAtIndexPaths
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Row selected: %d", [tableView indexPathForSelectedRow] row]);
NSLog(#"Section selected: %d", [tableView indexPathForSelectedRow] section]);
//return a custom cell for the row selected
}
When I try to access/log the indexPathForSelectedRow from within the cellForRowAtIndexPath, it returns 0,0 no matter which cell I select. Why is this?
Your call to reloadRowsAtIndexPaths: will cause the table view to reload the given cells and therefore cause the table to no longer have a selected row at that position. The cellforRowAtIndexPath method is a request from the data source to provide a row for the given index path. If you need to determine if a cell was selected prior to the request, you could store the indexPath of the selected row in a member. Then check the member in your cellForIndexPathMethod.
The following code sample assumes you are using ARC for memory management.
- (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.textLabel.text = [NSString stringWithFormat:#"Cell %d_%d", indexPath.section, indexPath.row];
// Configure the cell...
if(selectedIndexPath != nil) {
NSLog(#"Selected section:%d row:%d", selectedIndexPath.section, selectedIndexPath.row);
//TODO:Provide a custom cell for the selected one.
//Set the selectedIndexPath to nil now that it has been handled
selectedIndexPath = nil;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Store the selected indexPath
selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

didSelectRowAtIndexPath selecting more than one row at a time

I have a UITableView populated with 27 rows. I am trying to change the accessoryType of the selected cell. I do that in the didSelectRowAtIndexPath: delegate method.
The problem I am facing is that, when selecting a row and changing the accessoryType of the cell, the eleventh row from that row also gets modified.
I have tried printing the [indexPath row] value, but it's showing only the row that was selected and not another one.
I am really puzzled by such stuff; please help me out.
ADDED THE CODE cellForRowAtIndexPath method
UITableViewCell *cell;
if ([indexPath row] == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"acell"];
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:#"bcell"];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (cell == nil && [indexPath row] != 0) {
cell = [[[UITableViewCell alloc] initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:#"bcell"] autorelease];
}
else if(cell == nil && [indexPath row] == 0){
cell = [[[UITableViewCell alloc] initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:#"acell"] autorelease];
}
if ([cell.contentView subviews]){
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
}
if ([indexPath row] == 0) {
cell.textLabel.text = #"Select All";
cell.textLabel.font = [UIFont boldSystemFontOfSize:13.0f];
}
else {
cell.textLabel.text = #"Some Text Here"
cell.detailTextLabel.text = #"Another piece of text here"
}
return cell;
I am doing %10 because the behaviour is repeating after 11th row, hence trying to create new object for every 11th row.
My didSelectRowAtIndexPath methos code is
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
if ([indexPath row] != 0) {
NSIndexPath *tempIndex = [NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *tempCell = [tableView cellForRowAtIndexPath:tempIndex];
tempCell.accessoryType = UITableViewCellAccessoryNone;
}
cell.accessoryType = UITableViewCellAccessoryNone;
}
else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
if ([indexPath row] == 0) {
for (int i = 0; i < [dataSource count]; i++) {
NSIndexPath *tempIndex = [NSIndexPath indexPathForRow:i+1 inSection:0];
UITableViewCell *tempCell = [tableView cellForRowAtIndexPath:tempIndex];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
tempCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
tempCell.accessoryType = UITableViewCellAccessoryNone;
}
}
}
Please help me in multiple selection or anyother way to solve the problem of multiple selection.
Thanks in advance!!
Here's one way to do it:
- (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 setText:[NSString stringWithFormat:#"Row %d", indexPath.row]];
NSIndexPath* selection = [tableView indexPathForSelectedRow];
if (selection && selection.row == indexPath.row) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
Remember every cell in the table view is actually the same object being re-used. If you don't set the accessory type every time cellForRowAtIndexPath is called, when new cells scroll onto the screen they're going to all have the same accessory.
Multiple Select
For multiple selection it's a bit more complicated.
Your first option: Undocumented API
Note that this only works when the table's in editing mode. Set each cell's editing style to the undocumented UITableViewCellEditingStyleMultiSelect. Once you do that, you can get the table view's selection via an undocumented member of UITableView: indexPathsForSelectedRows. That should return an array of the selected cells.
You can expose this bit of functionality by putting this in a header:
enum {
UITableViewCellEditingStyleMultiSelect = 3,
};
#interface UITableView (undocumented)
- (NSArray *)indexPathsForSelectedRows;
#end
Then set the editing style for each cell like so:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleMultiSelect;
}
When the table is in editing mode you'll see the multi-select controls on your cells.
To look through other undocumented API, you can use the nm command line utility like this:
nm /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit
Your second option: Manage the selection yourself
Have your UITableView subclass contain an array that indicates which cells are selected. Then in cellForRowAtIndexPath, configure the cell's appearance using that array. Your didSelectRowAtIndexPath method should then look something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView indexPathIsSelected:indexPath]) {
[tableView removeIndexPathFromSelection:indexPath];
} else {
[tableView addIndexPathToSelection:indexPath];
}
// Update the cell's appearance somewhere here
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
This assumes you create indexPathIsSelected, removeIndexPathFromSelection, and addIndexPathToSelection methods in your UITableView subclass. These methods should do exactly what their names imply: Add, remove, and check for index paths in an array. You wouldn't need a didDeselectRowAtIndexPath implementation if you go with this option.
Remember every cell in the table view is actually the same object being re-used. If you don't set the accessory type every time cellForRowAtIndexPath is called, when new cells scroll onto the screen they're going to all have the same accessory." - daxnitro
This is where I got caught. I had mine set up so that in my "cellForRowAtIndexPath" function, I would only change the accessory for those specified in my array of checked cells, when what I should have done was update the accessory for all cells in the table.
In other words:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//normal set up
//retrieve key
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
id obj = [settings objectForKey:#yourKey];
//if the array is not populated, keep standard format for all cells
if (obj == nil){
selectedStyles = [[NSMutableArray alloc] initWithObjects:nil];
[cell setAccessoryType:UITableViewCellAccessoryNone]; //no check mark
[cell textLabel].textColor = [[UIColor alloc] initWithRed:0.0/255 green:0.0/255 blue:0.0/255 alpha:1.0]; //keep black color
}
//else retrieve information from the array and update the cell's accessory
else{
//if the cell is in your array, add a checkbox
[cell setAccessoryType:UITableViewCellAccessoryCheckmark]; //add check box
[cell textLabel].textColor = [[UIColor alloc] initWithRed:50.0/255 green:79.0/255 blue:133.0/255 alpha:1.0]; //change color of text label
//if the cell is not in your array, then keep standard format
[cell setAccessoryType:UITableViewCellAccessoryNone]; //no check mark
[cell textLabel].textColor = [[UIColor alloc] initWithRed:0.0/255 green:0.0/255 blue:0.0/255 alpha:1.0]; //keep black color
Hope this helps!