将超过一半的单元格移动到另一个部分时,Tableview 崩溃

Posted

技术标签:

【中文标题】将超过一半的单元格移动到另一个部分时,Tableview 崩溃【英文标题】:Tableview crashes when moving more than half the cells to another section 【发布时间】:2012-12-26 03:21:08 【问题描述】:

基本上,我正在尝试编写一个应用程序,它的 tableview 包含两个部分,一个包含未完成的任务(单元格),另一个包含已完成的任务。每个单元格都有一个复选框 UIButton 子类。问题是当我检查超过一半的项目时,它会因 NSRangeException 而崩溃。对于这个问题,我非常感谢任何建议。

错误:* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“* -[__NSArrayM objectAtIndex:]:索引 9 超出范围 [0 .. 8]”

CheckMarkTapped 方法(用于切换项目):

-(void)checkMarkTapped:(UIButton *)sender 

    UITableViewCell *cell = ((UITableViewCell *)[sender superview]);
    NSIndexPath *originIndexPath = [self.tableView indexPathForCell:cell];
    NSIndexPath *destinationIndexPath;

    NSLog(@"originIndexPath row: %i, section: %i", originIndexPath.row, originIndexPath.section);

    [self fixAllCheckboxes];

    if (originIndexPath.section == 0) 

        destinationIndexPath = [NSIndexPath indexPathForRow:[completedItems count] inSection:1];
        [sender setSelected:NO];

        NSMutableDictionary *tempDict = [[NSDictionary dictionaryWithDictionary:[uncompletedItems objectAtIndex:originIndexPath.row]]mutableCopy];
        [completedItems addObject:tempDict];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:destinationIndexPath, nil] withRowAnimation:UITableViewRowAnimationLeft];
        [uncompletedItems removeObjectAtIndex:originIndexPath.row];


    

    if (originIndexPath.section == 1)  //if the checkbox is in section 1
        [sender setSelected:YES];

        NSMutableDictionary *tempDict = [NSDictionary dictionaryWithDictionary:[[completedItems objectAtIndex:originIndexPath.row]mutableCopy]];

        destinationIndexPath = [NSIndexPath indexPathForRow:[[tempDict objectForKey:@"index"]intValue] inSection:0];
        [uncompletedItems insertObject:tempDict atIndex:[[tempDict objectForKey:@"index"]intValue]];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:destinationIndexPath, nil] withRowAnimation:UITableViewRowAnimationLeft];
        [completedItems removeObjectAtIndex:[self.tableView indexPathForCell:cell].row];

    

    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:originIndexPath, nil] withRowAnimation:UITableViewRowAnimationLeft];

CELLFORROWATINDEXPATH 方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell";

    if (indexPath.section == 1) 
        CellIdentifier = @"Cell1";
    

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.showsReorderControl = YES;
    

    for (UIControl *checkbox in [cell subviews]) 
        if (checkbox.tag == 9001) 
            [checkbox removeFromSuperview];
        
    

    if (indexPath.section == 0) 
        UIButton *checkbox = [[UIButton alloc]initWithFrame:CGRectMake(5, 5, 40, 40)];
        [checkbox addTarget:self action:@selector(checkMarkTapped:) forControlEvents:UIControlEventTouchUpInside];
        [cell setIndentationWidth:45];
        [cell setIndentationLevel:1];

        [checkbox setTag:9001];
        [checkbox setImage:[UIImage imageNamed:@"unchecked"] forState:UIControlStateNormal];
        [checkbox setImage:[UIImage imageNamed:@"checked"] forState:UIControlStateSelected];

        [cell addSubview:checkbox];

        cell.textLabel.backgroundColor = [UIColor whiteColor];
        cell.textLabel.backgroundColor = [UIColor whiteColor];
        cell.contentView.backgroundColor = [UIColor whiteColor];
        cell.textLabel.font = [UIFont boldSystemFontOfSize:20];

        switch (indexPath.section) 
            case 0:
                cell.textLabel.text = [[uncompletedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
                break;
            case 1:
                cell.textLabel.text = [[completedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
                [checkbox setSelected:YES];
                break;
            default:
                break;
        

        [cell addSubview:checkbox];

     else if (indexPath.section == 1) 

        UIButton *checkbox = [[UIButton alloc]initWithFrame:CGRectMake(5, 5, 40, 40)];
        [checkbox addTarget:self action:@selector(checkMarkTapped:) forControlEvents:UIControlEventTouchUpInside];
        [cell setIndentationWidth:45];
        [cell setIndentationLevel:1];
        [checkbox setTag:9001];

        cell.textLabel.backgroundColor = [UIColor whiteColor];
        cell.textLabel.backgroundColor = [UIColor whiteColor];
        cell.contentView.backgroundColor = [UIColor whiteColor];
        cell.textLabel.font = [UIFont boldSystemFontOfSize:20];
        cell.textLabel.text = [[uncompletedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];

        [checkbox setImage:[UIImage imageNamed:@"unchecked"] forState:UIControlStateNormal];
        [checkbox setImage:[UIImage imageNamed:@"checked"] forState:UIControlStateSelected];

        [cell addSubview:checkbox];

        switch (indexPath.section) 
            case 0:
                cell.textLabel.text = [[uncompletedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
                break;
            case 1:
                cell.textLabel.text = [[completedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
                [checkbox setSelected:YES];
                break;
            default:
                break;
        

        [cell addSubview:checkbox];
    
    return cell;

这是崩溃的 NSLog。如您所见,当数组具有相同数量的项目时会发生这种情况:

2012-12-26 12:54:44.583 Checklist R4[1128:c07] Destination Row: 0, UnCompleted Count: 19, Completed Count: 1
2012-12-26 12:54:45.034 Checklist R4[1128:c07] Destination Row: 1, UnCompleted Count: 18, Completed Count: 2
2012-12-26 12:54:45.454 Checklist R4[1128:c07] Destination Row: 2, UnCompleted Count: 17, Completed Count: 3
2012-12-26 12:54:45.873 Checklist R4[1128:c07] Destination Row: 3, UnCompleted Count: 16, Completed Count: 4
2012-12-26 12:54:46.294 Checklist R4[1128:c07] Destination Row: 4, UnCompleted Count: 15, Completed Count: 5
2012-12-26 12:54:47.072 Checklist R4[1128:c07] Destination Row: 5, UnCompleted Count: 14, Completed Count: 6
2012-12-26 12:54:47.399 Checklist R4[1128:c07] Destination Row: 6, UnCompleted Count: 13, Completed Count: 7
2012-12-26 12:54:48.085 Checklist R4[1128:c07] Destination Row: 7, UnCompleted Count: 12, Completed Count: 8
2012-12-26 12:54:48.621 Checklist R4[1128:c07] Destination Row: 8, UnCompleted Count: 11, Completed Count: 9
2012-12-26 12:54:49.090 Checklist R4[1128:c07] Destination Row: 9, UnCompleted Count: 10, Completed Count: 10
2012-12-26 12:54:50.234 Checklist R4[1128:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 9 beyond bounds [0 .. 8]'

【问题讨论】:

两件事:首先显示或说明您返回了多少行/部分,其次说明您在哪一行代码中得到异常(如果您不知道它添加异常断点)。 【参考方案1】:

您的 completedItemsuncompletedItems 数组,其中任何一个只有 8 个项目,但您尝试访问的项目不止于此。检查你的numberOfRowsInSection 方法,给出它们的动态值,比如

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    int rowCount = 0;
    if (section == 0) 
        rowCount = [uncompletedItems count];
     else 
        rowCount = [completedItems count];
    
    return rowCount;

而且它不需要 switchif 。使用任何人来检查您的 section 是 0 还是 1。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

static NSString *CellIdentifier = @"Cell";

if (indexPath.section == 1) 
    CellIdentifier = @"Cell1";


UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    cell.showsReorderControl = YES;


for (UIControl *checkbox in [cell subviews]) 
    if (checkbox.tag == 9001) 
        [checkbox removeFromSuperview];
    


    UIButton *checkbox = [[UIButton alloc]initWithFrame:CGRectMake(5, 5, 40, 40)];
    [checkbox addTarget:self action:@selector(checkMarkTapped:) forControlEvents:UIControlEventTouchUpInside];
    [cell setIndentationWidth:45];
    [cell setIndentationLevel:1];

    [checkbox setTag:9001];
    [checkbox setImage:[UIImage imageNamed:@"unchecked"] forState:UIControlStateNormal];
    [checkbox setImage:[UIImage imageNamed:@"checked"] forState:UIControlStateSelected];

    [cell addSubview:checkbox];

    cell.textLabel.backgroundColor = [UIColor whiteColor];
    cell.textLabel.backgroundColor = [UIColor whiteColor];
    cell.contentView.backgroundColor = [UIColor whiteColor];
    cell.textLabel.font = [UIFont boldSystemFontOfSize:20];

    switch (indexPath.section) 
        case 0:
            cell.textLabel.text = [[uncompletedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
            break;
        case 1:
            cell.textLabel.text = [[completedItems objectAtIndex:indexPath.row]objectForKey:@"Name"];
            [checkbox setSelected:YES];
            break;
        default:
            break;
    

    [cell addSubview:checkbox];

return cell;

【讨论】:

我检查了 cellForRowAtIndexPath 方法,发现它没问题。还有其他想法吗? 尝试设置Symbolic Breakpoints。我在您的代码中找不到什么问题。因为在您的按钮操作中,您有时会添加并且有时会插入。 Symbolic Breakpoints 会告诉你代码崩溃的地方。【参考方案2】:

你的代码可能有两个问题

    You are returning numbers of rows to Table View less then your array count. Your array is exceeding from the numbers of rows in Table View.

您描述的error 清楚地表明您的数组有8indexes,但您正在访问导致错误的9th

【讨论】:

我得到了导致错误的原因,但我无法弄清楚为什么它正在访问不存在的第九个索引。此外,奇怪的是,这仅在两个部分中存在相同项目时才会发生。 好的,一个快速的解决方案是我们可以进行检查,仅当index 小于Array count 时才在tableView 中插入数据。 它没有用。之前就崩溃了。我编辑了帖子以包括它崩溃的地方。

以上是关于将超过一半的单元格移动到另一个部分时,Tableview 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

将集合视图中的单元格移动到另一部分的最后一个单元格之外不起作用

如何组织表格视图单元格

将数据从一个工作簿复制并粘贴到另一个工作簿,导致随机单元格获取数据/空行而不会粘贴数据

pandas Dataframe,将特定值从一个单元格移动到另一个单元格

当它从一个 collectionView 移动到另一个时,如何实现单元格动画?

需要 VBA 代码才能单击将内容从一个单元格移动到另一个单元格的按钮