保留UITableViewCell选择状态

为什么UITableViewCell在选择,滚动,然后向后滚动后不重新加载复选标记?

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { #define CHECK_NULL_STRING(str) ([str isKindOfClass:[NSNull class]] || !str)?@"":str static NSString *CellIdentifier = @"inviteCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; cell.accessoryType = UITableViewCellAccessoryCheckmark; cell.textLabel.highlightedTextColor = [UIColor colorWithHexString:@"#669900"]; cell.selectionStyle = UITableViewCellSelectionStyleGray; cell.backgroundColor = [UIColor blackColor]; cell.textLabel.textColor = [UIColor whiteColor]; [[UITableViewCell appearance] setTintColor:[UIColor colorWithHexString:@"#669900"]]; if (cell == nil) { cell = [[UITableViewCell alloc] init]; } if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } BOOL isSearching = tableView != self.tableView; NSArray *arrayToUse = (isSearching ? searchResults : contactsObjects); id p = arrayToUse[indexPath.row]; NSString *fName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName)); NSString *lName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName)); cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", CHECK_NULL_STRING(fName), CHECK_NULL_STRING(lName)]; BOOL showCheckmark = [[stateArray objectAtIndex:indexPath.row] boolValue]; if (showCheckmark == YES) { cell.accessoryType = UITableViewCellAccessoryCheckmark; NSLog(@"It hit showCheckmark = YES, and stateArray is %@",stateArray[indexPath.row]); } else { cell.accessoryType = UITableViewCellAccessoryNone; NSLog(@"It hit showCheckmark = NO, and stateArray is %@",stateArray[indexPath.row]); } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; { id object = contactsObjects[indexPath.row]; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell.accessoryType == UITableViewCellAccessoryNone) { cell.accessoryType = UITableViewCellAccessoryCheckmark; [stateArray insertObject:[NSNumber numberWithBool:YES] atIndex:indexPath.row]; [selectedObjects addObject:object]; } else { cell.accessoryType = UITableViewCellAccessoryNone; [stateArray insertObject:[NSNumber numberWithBool:NO] atIndex:indexPath.row]; [selectedObjects removeObject:object]; } //slow-motion selection animation. [tableView deselectRowAtIndexPath:indexPath animated:YES]; } 

你错过了! (逆运算符)在以下行中表示状态将始终相同。

 [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:[[stateArray objectAtIndex:indexPath.row] boolValue]]]; 

它应该是

 [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]]; 

编辑—我重构了这两种方法,因为它可以用很少的代码完成,它将完全简化你的方法。

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"inviteCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; BOOL isSearching = tableView != self.tableView; NSArray *arrayToUse = (isSearching ? searchResults : contactsObjects); id p = arrayToUse[indexPath.row]; NSString *fName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName)); NSString *lName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName)); cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", CHECK_NULL_STRING(fName), CHECK_NULL_STRING(lName)]; BOOL showCheckmark = [stateArray[indexPath.row] boolValue]; if (showCheckmark == YES) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } else { cell.accessoryType = UITableViewCellAccessoryNone; } return cell; } - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { id object = contactsObjects[indexPath.row]; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell.accessoryType == UITableViewCellAccessoryNone) { cell.accessoryType = UITableViewCellAccessoryCheckmark; [selectedObjects addObject:object]; } else { cell.accessoryType = UITableViewCellAccessoryNone; [selectedObjects removeObject:object]; } stateArray[indexPath.row] = @(cell.accessoryType == UITableViewCellAccessoryCheckmark); } 

我建议采用更加面向对象的方法。 这将确保您的代码具有灵活性并始终正确显示。

对于要在表格中显示的每个项目,请使用相应的对象。 您提到您正在显示联系人,因此我们假设您的对象名为“联系人”:

 //Contact.h @interface Contact : NSObject @property BOOL selected; @property NSString *name; @end //Contact.m #import Contact.h @implementation Contact + (id) contactWithName:(NSString*)name { Contact *nContact = [Contact new]; nContact.name = name; nContact.selected = NO; return nContact; } @end 

然后,只需使您的视图工作如下:

 //ContactView.m @interface ContactView() @property NSMutableArray *contacts; @end @implementation ContactView @synthesize contacts; - (void) viewDidLoad { [super viewDidLoad]; //get your contact list here. When creating contacts, be sure to assign their selected and their name as you require. contacts = @[[Contact contactWithName:@"John"], [Contact contactWithName:@"Jane"]]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"inviteCell"; UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; Contact *cellContact = [contacts objectAtIndex:indexPath.row]; cell.textLabel.text = cellContact.name; cell.accessoryType = cellContact.selected == YES ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { Contact *cellContact = [contacts objectAtIndex:indexPath.row]; cellContact.selected = !cellContact.selected; [contacts replaceObjectAtIndex:indexPath.row withObject:cellContact]; [tableView reloadData]; //to refresh without animation //[tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableView numberOfSections])] withRowAnimation:UITableViewRowAnimationTop]; //to refresh with animation } @end 

繁荣,易于使用的表总是看起来正确,排队正确,并且面向对象以便以后轻松维护。

即使用replaceWithObject替换了insertObject ,单元格选择问题也没有解决,但是,不应该浪费时间在NSMutableArray使用NSInteger设置BOOL对象。 相反,对于单元格选择内存,应该像这样使用NSDictionary

 @property (nonatomic, strong) NSMutableDictionary * selectedRowCollection; - (void)viewDidLoad{ self.selectedRowCollection = [[NSMutableDictionary alloc] init]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; { id object = contactsObjects[indexPath.row]; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell.accessoryType == UITableViewCellAccessoryNone) { cell.accessoryType = UITableViewCellAccessoryCheckmark; [self.selectedRowCollection setObject:@"1" forKey:[NSString stringWithFormat:@"%d",indexPath.row]]; } else { cell.accessoryType = UITableViewCellAccessoryNone; [self.selectedRowCollection removeObjectForKey:[NSString stringWithFormat:@"%d",indexPath.row]]; } //slow-motion selection animation. [tableView deselectRowAtIndexPath:indexPath animated:YES]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { BOOL showCheckmark = [[self.selectedRowCollection valueForKey:[NSString stringWithFormat:@"%d",indexPath.row]] boolValue]; if (showCheckmark == YES) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } else { cell.accessoryType = UITableViewCellAccessoryNone; } } 

你没有这样做UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } 如果单元格为零,则需要分配。 或者在滚动时导致问题。