混合使用静态和动态UITableViewController内容会导致NSRangeException [英] Mixing static and dynamic UITableViewController content causes NSRangeException

查看:52
本文介绍了混合使用静态和动态UITableViewController内容会导致NSRangeException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找这个错误,确实发现了一些行为类似但没有解决问题的解决方法的帖子.

I have been searching all over for this error and did find some few posts with a similar behavior but no solution that solves the problem.

我有一个UITableViewController(在SB中声明为Static),它必须具有Sections:Section 0(Recipe)是具有4个单元格的静态,Section 1(Flavours)应该是动态的

I have a UITableViewController (declared as Static in SB) which has to Sections: Section 0 (Recipe) is static with 4 cells, Section 1 (Flavours) should be dynamic

这是我要测试的代码:

- (void)viewDidLoad {
    [super viewDidLoad];

    rows = [[NSMutableArray alloc] initWithArray:@[@"test",@"test",@"test",@"test",@"test",@"test",@"test"]];
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
    switch (section) {
        case 0:
        return 4;
        break;
        case 1:
        return rows.count;
        break;

        default:
        break;
    }

    return 1;
}

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

    UITableViewCell *cell;

    switch (indexPath.section) {
        case 0:
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];
        break;

        case 1:

        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
        if (!cell)
        {
// create a cell
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
        }
        cell.textLabel.text = [rows objectAtIndex:indexPath.row];
        return cell;

        default:
        break;
    }

    return cell;
}

现在,我在运行时遇到的错误是:'NSRangeException',原因:'***-[__ NSArrayI objectAtIndex:]:索引1超出了[0 .. 0]'

Now the error I'm getting when running is: 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

我知道我在某个地方想念一些小东西,有人可以帮我吗?

I know I miss something small somewhere, can someone help me?

非常感谢

推荐答案

实际的问题是动态和静态tableViewControllers的工作方式.

The actual problem is the way how dynamic and static tableViewControllers work.

如果创建动态UITableViewController,则大多数方法将返回nil或0或另一个默认值.因此,如果不在您的UITableViewController子类中覆盖它们,那么也不会发生任何不好的事情.

If you create a dynamic UITableViewController, most methods return nil or 0 or another default value. So nothing bad happens if you don't overwrite them in your UITableViewController subclass.

如果创建静态UITableViewController,则大多数方法会询问"情节提要中返回的内容.实际上,可能有一个像私有阵列这样的后备存储,其中包含所有必要的数据.而且,如果您不覆盖查询此后备存储的方法,则默认实现将向数组询问不存在的索引处的对象.

If you create a static UITableViewController, most methods "ask" the storyboard what to return. In reality there is probably something like a private array as a backing store that contains all the necessary data. And if you don't overwrite methods that query this backing store the default implementation will ask the array for objects at indexes that don't exist.

您的问题是,您告诉tableView它具有2个部分和几行.因此,tableView向静态UITableViewController询问第二部分第二行中的单元格高度之类的信息.但是此indexPath在静态tableView所使用的后备存储区中不存在(因为您仅在第二部分中放入了一行).

Your problem is that you tell the tableView that it has 2 sections and a couple of rows. So the tableView asks the static UITableViewController about things like the height of the cell in second row in second section. But this indexPath does not exist in the backing store (because you only put a single row into the second section) that is used by the static tableView.

因此,如果tableView要访问静态表存储中不存在的信息,则必须实现几个dataSource和委托方法并返回自己的值.

So you have to implement a couple of dataSource and delegate methods and return your own values if the tableView wants to access information that does not exist in the static table store.

如果您查看异常的调用堆栈,您应该能够看到这些方法.

If you look at the call stack of the exception you should be able to see these methods.

例如:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
    0   CoreFoundation    0x000000010ebaaf35 __exceptionPreprocess + 165
    1   libobjc.A.dylib   0x000000010e843bb7 objc_exception_throw + 45
    2   CoreFoundation    0x000000010eaa301e -[__NSArrayI objectAtIndex:] + 190
    3   UIKit             0x000000010f4dc856 -[UITableViewDataSource tableView:heightForRowAtIndexPath:] + 109
    4   UIKit             0x000000010f21026b __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 302
    5   UIKit             0x000000010f20f8fe -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4125
    6   UIKit             0x000000010f214e45 -[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:] + 320
    7   UIKit             0x000000010f214f3a -[UITableViewRowData heightForTable] + 56

在调用堆栈的索引3处,您可以看到-[UITableViewDataSource tableView:heightForRowAtIndexPath:]已调用引发异常的objectAtIndex:代码.如果您不阻止他们将调用转移到后端存储,则这是一种方法.因此,您必须实现此方法并返回有用的东西.然后继续,直到没有更多的例外为止.

At index 3 of the call stack you can see that -[UITableViewDataSource tableView:heightForRowAtIndexPath:] has called the objectAtIndex: code that raised the exception. This is one of the methods that relay their calls to the backend store if you don't stop them from doing that. So you have to implement this method and return something usefull. And then you continue until there are no more exceptions.

所需的方法数量可能取决于tableView的配置.我实现了通常会导致这些异常的四种方法,因此,如果您看到更多由未覆盖的UITableViewDataSource/Delegate方法引起的异常,则可以看到应该遵循的模式:

How many methods are required might depend on the configuration of your tableView. I implemented the four that usually cause these exceptions, so you can see the pattern you should follow if you see more exceptions that are caused by not overwritten UITableViewDataSource/Delegate methods:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    CGFloat height = 0;
    if (section == 0) {
        // static section
        height = [super tableView:tableView heightForHeaderInSection:section];
    }
    return height;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    CGFloat height = 0;
    if (section == 0) {
        // static section
        height = [super tableView:tableView heightForFooterInSection:section];
    }
    return height;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat height = 44;
    if (indexPath.section == 0) {
        // static section
        height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
    }
    return height;
}

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSInteger indentationLevel = 0;
    if (indexPath.section == 0) {
        // static section
        indentationLevel = [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
    }
    return indentationLevel;
}


这是使您的静态内容与代码更加独立的一个小技巧:


and here is a little trick to make your static content even more independent from your code:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        // static section
        return [super tableView:tableView numberOfRowsInSection:section];
    }
    return self.objects.count;
}

如果混合使用动态和静态单元格,则调用super会非常有用.

If you mix dynamic and static cells, calling super becomes very useful.

这篇关于混合使用静态和动态UITableViewController内容会导致NSRangeException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆