5

我正在制作一个自定义 UITableView 菜单选择器组件。每次选择特定行时,我都会保存该行的索引路径,以便用户下次选择另一行时,人们可以知道他之前选择的行。所以我将它添加到 cellForRowAtIndexpath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    cell.textLabel.text = self.left[indexPath.row][@"name"];
    [tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:[[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow] integerValue] inSection:0] animated:YES scrollPosition:UITableViewScrollPositionNone];
    cell.selectionStyle = UITableViewCellSelectionStyleGray;
    cell.textLabel.highlightedTextColor = [UIColor grayColor];
    return cell;
}

当用户选择另一行时,将此行保存到:[[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow],以便下次他可以看到他之前选择的行。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:indexPath.row] forKey:kPreviousSelectedRow];
}

崩溃日志:索引为 [[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow] integerValue],计数为 numberOfRows。如您所见,它不应该超出范围。我不知道 [0...6] 来自哪里。

2013-08-23 21:01:26.107 [17605:c07] index:10, count:14
2013-08-23 21:01:26.173[17605:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 7 beyond bounds [0 .. 6]'

编辑:如果我缓慢滚动表格视图,它不会崩溃,如果我快速滚动它,它会崩溃。什么?

4

6 回答 6

2

您会崩溃,因为此时您没有具有指定索引的单元格,因为您只是在您的内部准备它- (UITableViewCell*)tableView:cellForRowAtIndexPath:

为了获得您期望selectRowAtIndexPath:的行为- (UITableViewCell*)tableView:cellForRowAtIndexPath:并将其放置在另一个方法中,您正在更新您的UITableView:-(void)viewDidLoad或您调用-(void)reloadTable的地方

于 2013-08-23T12:55:00.567 回答
1

您的应用程序正在崩溃,因为它试图选择当前可能不可见的行。当数据可能尚未完全可用时,您正尝试在数据源方法“cellForRowAtIndexPath”中选择一行。这就是为什么你得到越界错误。

对于您的具体示例,您可以在更新值之前尝试在“didSelectRowAtIndexPath”中选择先前选择的行,因为您的数据已经显示,它不会在此处崩溃。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{   
    [tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:[[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow] integerValue] inSection:0] animated:YES scrollPosition:UITableViewScrollPositionNone];
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:indexPath.row]     forKey:kPreviousSelectedRow];
}
于 2013-08-23T13:33:34.263 回答
1

SVGreg 是对的。您应该在另一种方法中使用单元格。但 viewDidLoad 不是最佳选择。你可以试试这个有用的委托方法

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

    [tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:[[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow] integerValue] inSection:0] animated:YES scrollPosition:UITableViewScrollPositionNone];
    cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
于 2016-01-14T19:14:48.433 回答
0

哦,我只是将selectRowAtindex替换为layoutsubview,现在它不会崩溃。感谢 SVGreg 的提示。

于 2013-08-23T13:28:10.333 回答
0
[tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:[[[NSUserDefaults standardUserDefaults] objectForKey:kPreviousSelectedRow] integerValue] inSection:0] animated:YES scrollPosition:UITableViewScrollPositionNone];

不应该在里面cellForRowAtIndexpath

每次用户选择一个单元格时都会触发你indexPath的。didSelectRowAtIndexPath如果您想在用户取消选择一个单元格或选择另一个单元格时触发另一种方法,请使用

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
于 2013-08-23T12:54:15.173 回答
0

您可以制作一个容量等于您的行数的数组。可能用 NO BOOL 值填充它(实际上是 [NSnumber numberWithBool:] 因为它们需要是对象)。

然后在

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

更改 indexPath.row 位置处对象的值,

而在

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

检查数组中的 BOOL 值是否设置为 YES,然后选择单元格。(cell.selected = YES)

您可以加倍努力,使用自定义选择样式或其他内容制作自定义单元格,并在单元格上创建一个方法,该方法将应用您选择的设计并在 cellForRowAtIndexPath 中调用该方法。

于 2013-08-23T13:08:32.387 回答