自动展开 UITableView - NSRangeException

Posted

技术标签:

【中文标题】自动展开 UITableView - NSRangeException【英文标题】:Automatically expand UITableView - NSRangeException 【发布时间】:2009-09-21 00:09:55 【问题描述】:

我有一个绑定到我的 uitableview 的 SQLite 数据库。大约有 2000 行,所以我首先检索 25 行。一旦我滚动到列表的末尾,我希望它自动检索 25 多行。

这是我现在使用的方法。忽略如果我加载所有 2000 行会发生什么,我稍后会担心。在tableView:numberOfRowsInSection: 中,我返回的比当前加载的行多一个。然后在tableView:cellForRowAtIndexPath: 中,如果加载最后一行,我会加载更多行。

通常我可以写几页,但我最终得到一个例外: *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (10) beyond bounds (10)'。该指数始终为 8-10。我不知道它是什么数组,但我的 rowsindices 数组都有超过 10 项。

tableView:cellForRowAtIndexPath:

if(indexPath.row >= [rows count]) 
    [cell.textLabel setText:@"Loading..."];
    if(!updating && indexPath.row == [rows count]) 
        updating = YES;
        [[self tableView] beginUpdates];
        NSMutableArray *indices = [NSMutableArray array];
        // stmt = ...
        while(sqlite3_step(stmt) == SQLITE_ROW) 
            [rows addObject:@"..."];
            [indices addObject:[NSIndexPath indexPathForRow:[rows count]-1 inSection:0]];
        
        [[self tableView] insertRowsAtIndexPaths:indices withRowAnimation:UITableViewRowAnimationNone];
        [[self tableView] endUpdates];
        updating = NO;
    
    return cell;

堆栈跟踪:

#0  0x01ce4004 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___ ()
#1  0x9779df49 in objc_exception_throw ()
#2  0x01cc5c3b in +[NSException raise:format:arguments:] ()
#3  0x01cc5b9a in +[NSException raise:format:] ()
#4  0x00072cc9 in _NSArrayRaiseBoundException ()
#5  0x00010227 in -[NSCFArray objectAtIndex:] ()
#6  0x0047fe5b in -[_UITableViewUpdateSupport(Private) _setupAnimationsForExistingVisibleCells] ()
#7  0x0047f9e0 in -[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:newRowData:oldRowRange:newRowRange:context:] ()
#8  0x002eca2b in -[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:] ()
#9  0x002ec757 in -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] ()
#10 0x002def56 in -[UITableView endUpdates] ()    

【问题讨论】:

【参考方案1】:

我有点不清楚你为什么要插入行。在我看来,您正在使这比需要的复杂得多。 UITableView 只会询问您屏幕上(或即将出现)的表格单元格的值。更重要的是,通过不断向表格视图添加行,滚动条并不能反映用户在数据集中的实际位置。

返回 tableView:numberOfRowsInSection: 中的总行数同样有意义(您可以使用 SQLite COUNT 聚合函数来执行此操作,而无需实际获取所有数据)并根据需要缓存其他数据(当您遇到“缓存未命中”时,使用类似于上面的内容。

如果我不得不猜测为什么这段代码会导致您出现问题,那可能是您正在修改表格视图的内容,而表格视图正在等待您返回一个单元格。

我会建议一些看起来更像这样的东西:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    if ([indexPath row] >= [cache count]) 
        // Load additional items into the cache
    

    // Do the regular cell setup stuff here; you can assume the data you need is available
    return cell;

【讨论】:

这是一个很好的解决方案!非常感谢!【参考方案2】:

Alex,我接受你的回答,尽管我仍然对导致实际异常的原因感兴趣。

您对在返回单元格时更新 tableview 的评论使我实现 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 以在需要时加载更多行,这更稳定,尽管我必须在单独的线程中这样做才能获得任何类型的性能。

您的解决方案也有效,而且肯定比我目前的方法更简单。我必须决定是否希望滚动条显示 实际 位置或更实际的位置。至少对我来说,当滚动条很小时,感觉应用程序正在加载许多对象,因此速度较慢。

【讨论】:

以上是关于自动展开 UITableView - NSRangeException的主要内容,如果未能解决你的问题,请参考以下文章

展开或折叠时可展开的 UItableview 内容高度不同

如何在 StackView 中展开 UITableView?

水平展开的uiscrollview还是uitableview?

UITableView实现分组, 并且点击每个分组后展开

展开/折叠带有支持 NSFetchedResultsController 的 UITableView 部分

iPhone UITableView 可展开/可折叠