带有 Sections [indexPath Row] 的 TableView 中的 NSRangeException 超出范围

Posted

技术标签:

【中文标题】带有 Sections [indexPath Row] 的 TableView 中的 NSRangeException 超出范围【英文标题】:NSRangeException in TableView with Sections [indexPath Row] goes out of range 【发布时间】:2013-05-01 22:09:53 【问题描述】:

这是打印到控制台的错误:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** 
-[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(0x27f0012 0x1a51e7e 0x27a5b44 0xde6d 0xe2f8fb 0xe2f9cf 0xe181bb 0xe28b4b 0xdc52dd 0x1a656b0 0x97efc0 0x97333c 0x973150 0x8f10bc 0x8f2227 0x99c333 0x99c75f 0x27af376 0x27aee06 0x2796a82 0x2795f44 0x2795e1b 0x22677e3 0x2267668 0xd74ffc 0x258d 0x24b5 0x1)
libc++abi.dylib: terminate called throwing an exception

程序恰好在以下位置中断:

NSString *cellValue = [models objectAtIndex:indexPath.row];

cellForRowAtIndexPath: 方法中

所有的tableview方法如下:

//---set the title for each section---
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 


     //countyIndex returns the number of counties per state
     //in the debugger I checked and the countyIndex is returning the correct number
     //of counties!
    return [countyIndex objectAtIndex:section];



-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    return [countyIndex count];


//---set the number of rows in each section---
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

    //---get the county in section---
    NSString *county = [countyIndex objectAtIndex:section];

    //---get all models from the county---
    NSPredicate *predicate = 
    [NSPredicate predicateWithFormat:@"countyName == %@", county];
    NSArray *mods = [modelArray filteredArrayUsingPredicate:predicate];

    //---return the number of models from the county---
    return [mods count];    


   //models appears to be counted as the number of objects per section


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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 

        cell = [[UITableViewCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:CellIdentifier];

    

    // now configure the cell


    //---get the county in the current section---
    NSString *county = [countyIndex objectAtIndex:[indexPath section]];

    //---get all models from the county---
    NSPredicate *predicate = 
    [NSPredicate predicateWithFormat:@"countyName == %@", county];
    NSArray *mods = [modelArray filteredArrayUsingPredicate:predicate];
    NSMutableArray *newModelArray = [[NSMutableArray alloc] init];
     for (NSManagedObject *obj in mods) 
         [newModelArray addObject:[NSString stringWithFormat:@"%@",[obj valueForKey: @"model"]]];
     


    //get rid of duplicates
    NSArray *objectsWithDuplicates = newModelArray;
    NSSet *duplicatesRemover = [NSSet setWithArray:objectsWithDuplicates];
    models = [duplicatesRemover allObjects];
    models = [models sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];


    UITableViewCell *bgView = [[UITableViewCell alloc] initWithFrame:CGRectZero];

    //cell.contentView.backgroundColor = [UIColor whiteColor];
    bgView.backgroundColor = [UIColor whiteColor];

    cell.backgroundView = bgView;
    cell.layer.borderColor = [[UIColor lightGrayColor] CGColor];      
    cell.layer.borderWidth  = .50;



    if ([models count]>0) 
        //---extract the relevant model from the model object---
        NSString *cellValue = [models objectAtIndex:indexPath.row];
        cell.textLabel.text = cellValue;

        [cell setAccessibilityTraits:UIAccessibilityTraitButton];

    
    return cell;


-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    //index path to row that's selected 
    NSIndexPath *myIndexPath = [self.sTable indexPathForSelectedRow];
    UITableViewCell *cell = [self.sTable cellForRowAtIndexPath:myIndexPath];
    labelText = cell.textLabel.text;
    selectedModel = cell.textLabel.text;


从控制台执行一些命令后:

po [型号数]

po (int)[indexPath row]

我看到当 [models count] 等于 2 并且 [indexPath row] 也等于 2 时它会中断,这当然会超出范围,因为 2 实际上是 3,因为表索引从 0 开始。

问题是,为什么会发生这种情况?在切换表值后,我已经重新加载了表数据,我检查并计算了每个部分的所有行数,它们看起来是正确的。那么为什么还会发生这种情况呢?奇怪的是,当我在表格中向下滚动时,重新调用 cellForRowAtIndexPath:(NSIndexPath *)indexPath 之后会发生这种中断。

这发生在 Xcode 4.6.1 中的所有模拟器 ios 5.0 - ios 6.1

**编辑:

我应该补充一点,这只发生在加利福尼亚州和威斯康星州。 我认为这将有助于缩小范围,但我检查了数据库,并且县和模型的数量与调试器中返回的内容相匹配。

【问题讨论】:

发生这种情况是因为 models 在您返回部分中的行数之前发生了变异,或者您返回了错误的行数......也许是因为您现在有多个部分?您没有包含该代码。 我有一个带有部分的表格视图。被计算的模型数量似乎是每个部分的数量。 您没有包含足够的代码来查看可能发生的情况...要么您告诉框架您拥有的模型比实际拥有的模型多,要么您正在丢失它们...可能是第一个 不是您返回给定部分的行数的部分... 【参考方案1】:

这是因为您在cellForRowAtIndexPath 中删除了重复项。但是您不会在numberOfRows 中这样做。因此cellForRow 中的模型数组比numberOfRows 中派生的计数短。

这是为什么 DRY 如此重要的一个典型案例:不要重复自己。用两种不同的方法做同样的事情,您不仅会浪费代码并使代码难以维护,而且还会冒着在这两个地方以不同方式做同样事情的风险。您应该分解为特定部分(县)派生实际模型的代码,以便只有 一个 方法可供您的其他两种方法参考。 (更好的方法是准备一个更好的模型,也许是:行和数组索引之间总是只有简单的一对一对应关系。)

【讨论】:

我正在检查这是否是导致问题的原因,我会告诉你它是如何工作的。 令人惊讶的是没有。我很震惊,因为我在其中添加了 removeDuplicates(它应该有 btw)所以应该导致错误......但即使在修复它之后它仍然给我一个 nsrangeexception! 我可能要跳崖了... :( 但说真的,它会是这样的。做我说的另一件事:重构,以便在两个地方以相同的方式派生模型。更好的是,正如我所说,使用相同的模型:提前准备模型,这样就没有区别了。这个必须计算两种方法中的模型的业务只是要求错误(并得到它,显然) 唯一的问题是我在这个视图中有一个选择器控制器,它包含所有状态,并且每次更改状态时都会列出所有带有机器模型的县。所以值会发生变化,这使得它们需要重新计算。

以上是关于带有 Sections [indexPath Row] 的 TableView 中的 NSRangeException 超出范围的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:带有变量的whereIn

tableView.reloadRows(at:[indexPath],带有:.none)会像这样崩溃吗?

错误:'inout IndexPath' 不能转换为 'IndexPath'

从UICollectionView cellForItemAt indexPath为CAShapeLayer动画设置toValue

NSFetchedResultsController didChangeObject indexPath 为空

IndexPath.row 对于静态单元格不是唯一的