iOS 11 UITableView didSelect行选中异常求助:Cell标签值被错误替换
问题分析与解决方案
嘿,我看了你的代码,发现几个关键问题导致iOS11下选中行后Label显示默认文本:
1. 数组越界导致的文本赋值失败
在cellForRowAtIndexPath里,你给lblName赋值时用了indexPath.row-1:
cell.lblName.text = [[arrpickuprequest objectAtIndex:indexPath.row-1]valueForKey:@"Name"];
但你的表格第一行(indexPath.row == 0)是全选/全不选的控制行,这时候indexPath.row-1等于-1,直接访问数组的负索引会导致未定义行为。iOS10可能刚好没触发崩溃,但iOS11的数组越界检查更严格,导致这行的lblName没有被正确赋值,显示成Label的默认文本;当你选中行触发reloadData后,其他复用的cell也可能因为这个错误导致数据显示异常。
2. UITableViewCell复用逻辑缺失
你的代码里没有正确复用cell,没有调用dequeueReusableCellWithIdentifier:来获取复用cell,这在iOS11的UITableView复用机制调整后,会导致cell的状态混乱,数据显示错误。
修正后的代码示例
首先修正cellForRowAtIndexPath方法
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ // 先获取复用cell,记得提前给cell设置identifier(比如在xib/storyboard里设置) static NSString *cellIdentifier = @"PickupRequestCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (!cell) { // 如果没有复用cell,再创建(如果是xib的话用initWithNibName,storyboard的话一般不需要这步) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; // 这里假设你的cell是自定义的,需要初始化lblName和btncheck // 比如:cell.lblName = [[UILabel alloc] initWithFrame:CGRectMake(...)]; // [cell.contentView addSubview:cell.lblName]; // 同理初始化btncheck } // 处理第一行(全选行) if (indexPath.row == 0) { cell.lblName.text = @"全选"; // 设置全选行的文本,或者你需要的默认文本 } else { // 其他行用indexPath.row-1访问arrpickuprequest cell.lblName.text = [[arrpickuprequest objectAtIndex:indexPath.row-1] valueForKey:@"Name"]; } // 处理复选按钮 cell.btncheck.tag = indexPath.row; if([[arrpickuprequestChecked objectAtIndex:indexPath.row] isEqualToString:@"Uncheck"]) { [cell.btncheck setImage:[UIImage imageNamed:@"uncheck"] forState:UIControlStateNormal]; } else { [cell.btncheck setImage:[UIImage imageNamed:@"check"] forState:UIControlStateNormal]; } // 注意:每次复用cell时,要先移除旧的target,避免重复添加 [cell.btncheck removeTarget:self action:@selector(purchase_click:) forControlEvents:UIControlEventTouchUpInside]; [cell.btncheck addTarget:self action:@selector(purchase_click:) forControlEvents:UIControlEventTouchUpInside]; cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; }
其次检查didSelectRowAtIndexPath的数组操作
确保arrpickuprequestChecked的元素数量始终是arrpickuprequest.count + 1(因为包含第一行的全选状态),初始化的时候要正确设置:
// 初始化示例 arrpickuprequestChecked = [[NSMutableArray alloc] init]; // 先添加第一行的初始状态 [arrpickuprequestChecked addObject:@"Uncheck"]; // 再给每个请求添加初始状态 for (int i=0; i<arrpickuprequest.count; i++) { [arrpickuprequestChecked addObject:@"Uncheck"]; }
另外,在didSelectRowAtIndexPath里的循环可以优化一下,避免越界:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { NSString *targetState = [[arrpickuprequestChecked objectAtIndex:0] isEqualToString:@"Uncheck"] ? @"Check" : @"Uncheck"; // 遍历所有行(包括第一行)设置状态 for (int i=0; i<arrpickuprequestChecked.count; i++) { [arrpickuprequestChecked replaceObjectAtIndex:i withObject:targetState]; } } else { NSString *currentState = [arrpickuprequestChecked objectAtIndex:indexPath.row]; NSString *newState = [currentState isEqualToString:@"Uncheck"] ? @"Check" : @"Uncheck"; [arrpickuprequestChecked replaceObjectAtIndex:indexPath.row withObject:newState]; // 如果取消选中某一行,要把全选行的状态改成Uncheck if ([newState isEqualToString:@"Uncheck"]) { [arrpickuprequestChecked replaceObjectAtIndex:0 withObject:@"Uncheck"]; } else { // 可选:检查是否所有行都被选中,如果是,把全选行改成Check BOOL allChecked = YES; for (int i=1; i<arrpickuprequestChecked.count; i++) { if ([[arrpickuprequestChecked objectAtIndex:i] isEqualToString:@"Uncheck"]) { allChecked = NO; break; } } if (allChecked) { [arrpickuprequestChecked replaceObjectAtIndex:0 withObject:@"Check"]; } } } [tblPickupreuest reloadData]; }
额外建议
- 尽量用
NSDictionary或者自定义模型来管理选中状态,而不是用字符串@"Check"/@"Uncheck",这样更安全易维护。 - 开启Xcode的Address Sanitizer(Product > Scheme > Edit Scheme > Run > Diagnostics > Address Sanitizer),可以快速检测数组越界等内存问题。
内容的提问来源于stack exchange,提问作者Niharika
相关产品推荐
相关产品推荐

