UITableView滚动导致应用程序崩溃

11

前言: 我对 iPhone SDK,Obj-C,Interface Builder 和 Cocoa 都是新手。我可能做了一些明显错误的事情。

问题: 我有一个 UITableView,当我滚动它时会崩溃。它只会滚动一点点来显示最底部半隐藏单元格的完整单元格,但不会加载下一个单元格。同样,如果我滚动到顶部完全隐藏最底部的单元格,并且它反弹回来以显示该单元格,则在显示之前会崩溃。这让我感到奇怪,因为它正确地绘制了前7个单元格中的数据。单元格数据在一个 NSArray 中,在 Interface Builder 中作为 UITableViewdataSourcedelegate 连接到 UITableViewController 中。它在视图初始化时工作正常。

我正在制作一个应用程序,本来以为2天前就能完成,它只是计算组合并在一个方便的可滚动表视图中显示它们的列表。现在,它甚至都没有计算出所有内容,DataSource 中的 NSArray 只初始化了一次,其中包含一些字符串,如 @"Hello"@"World"

复现步骤: 因为我在使用 IB,所以无法完全用代码展现整个故事。所以我会描述到目前为止我做了什么,并希望它不会让你昏昏欲睡。

在 Xcode 中新建一个 "Tab Bar Application",因为我想要2个选项卡,而且我不想要导航栏或全屏表格。我将 MainWindow.xib 的第一个选项卡视图移到 FirstView.xib 中作为给定的 SecondView.xib 的类比。这很好地解决了问题。我修改了视图,包含两个 UITextField 用于输入和一个 UITableView 用于输出。这起作用了,但表格是空的。我对 UITableViewController 进行了子类化,在其中填充了一个名为 combinationsNSArray 属性,其中包含11个字符串,然后添加了:

// Set up the cell...
cell.userInteractionEnabled = NO;
cell.text = [combinations objectAtIndex:indexPath.row];

在这里只有评论。我在IB中向FirstView.xib添加了一个Table View Controller,并将其类名设置为与此新子类的名称匹配,并将我的视图中的Table View拖到这个Combinations Table View Controller上两次。一次链接dataSource和一次链接delegate。如果只链接dataSource,则会获得相同的行为。

这将运行并使用dataSource combinations的前7个值填充表格的可见行(6.5)。我可以向下滚动0.5个单元格,然后向上滚动。但是,如果我向上或向下滚动超过0.5个单元格,应用程序将崩溃。报告中的解释如下:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[NSCFTimer tableView:cellForRowAtIndexPath:]:
unrecognized selector sent to instance 0x52ca40'

我没有创建一个NSCFTimer,也没有将其链接到我的Table View,我怀疑cellForRowAtIndexPath实际上应该是应该传递给我的dataSourcedelegate的消息,所以我很困惑它为什么会偏离轨道,并最终到达了哪里。

更新:感谢回答和评论。我的问题似乎是CombinationsTableViewControllerUITableViewController的子类)实际上没有在我的代码中任何特定的地方实例化。它确实在某个时候被创建(当加载FirstView.xib时),并且在初始tableView填充7个单元格时显然是受管理的,然后被释放。因此,我需要确定在哪里/如何制作对此控制器的保留引用。我的Application Delegate可能应该有一些持有此控制器的输出口,可以将其链接为在xib中的实例。是的,我是新手。我知道我可以通过避免IB并在代码中明确执行操作来消除这些麻烦,但我认为我想学会灵活使用IB。

最后:是的,我需要一个保留的表视图控制器实例。听起来很基础,但这在使用IB时并不明显。阅读我的帖子以了解整个过程和修复方法。

旁白:无论是调试器需要详细的说明(任何链接都会有所赞赏),还是它并不起作用。我似乎通过让应用程序崩溃并阅读它生成的报告来更快地获得更多信息。但这需要繁琐的终止、重新启动和3次单击。我真的想摆脱这个问题,转而进行输入电缆的接线、计算和每次更改后都更新表格。那才是难点,而不是使框架成员工作。

进一步的胡言乱语:这些都是在iPhone SDK 2.2.1中完成的。当时,没有免费的公共3.0 SDK可用,除非你为冷酷的现金加入俱乐部。我期望它在WWDC 2009开幕时就已经发布了,但事实上,直到今天(2009年7月17日)才发布了免费的公共3.0 SDK。


你是否将UITableView的代理设置为应用程序控制器? - Igor
6个回答

7

看起来你正在失去tableView代理。

看起来发生的情况是UITableViewDelegate被释放了,然后应用程序使用相同的指针地址进行NSCFTimer。
你是否在任何地方调用了delegate的release方法,或者如果它在自动释放池中,则没有保留delegate。


谢谢!当委托不是创建表格的相同控制器时(故意这样做),我也遇到了同样的问题。 - Jsdodgers

5

好的,如果您按照复制步骤,现在我将添加解决此问题的步骤:

解决此问题的步骤

  1. 子类化一个UIViewController。我称之为CombinationsViewController。在此控制器中,将combinationsTableViewController添加为IBOutlet属性,该属性来源于下面第6步。

  2. 不要忘记导入正确的内容,并合成表视图控制器,同时在dealloc方法中释放它。

  3. FirstView.xib中,将File's Owner类更改为此最新的子类。

  4. 将其combinationsViewController输出链接到FirstView.xib中第7步中创建的Combinations Table View Controller

  5. 在您的MainWindow.xib中打开TabBarController,选择第一个选项卡,在Identity Inspector中将类更改为最新的子类(CombinationsViewController)。

这样可以使表格正常填充和滚动。

现在我将继续进行一些自定义表视图单元格的操作,并实际使我的应用程序运行起来。

作为修复的枚举步骤供参考:

  1. 在Xcode中创建一个新的“选项卡应用程序”。

  2. 打开Tab View Controller,将第一个选项卡的预设视图拖到MainWindow.xib中。

  3. 创建一个基于视图的xib文件,名为FirstView.xib,类似于给定的SecondView.xib,并将该预设视图放入此xib文件中。

  4. 将该视图链接到File's Ownerview输出口。

  5. 修改该视图以包含两个输入UITextField和一个输出UITableView

  6. UITableViewController子类化为CombinationsTableView,其中我使用11个字符串填充了一个名为combinationsNSArray属性,然后添加了cell.text = [combinations objectAtIndex:indexPath.row];代码,其中原来只有有关设置单元格的注释。

  7. FirstView.xib中添加一个Table View Controller,并将其类名称设置为与此新子类名称相匹配,并将我的视图中的Table View分别拖动到此Combinations Table View Controller上两次。一次链接dataSource,一次链接delegate

此时表格确实会呈现数据,但滚动会出现问题。这是因为CombinationsTableView没有被任何地方保留。对于第一次使用IB的用户来说,这非常不清楚。因此,您需要应用上述修复方法。

第一个在答案中总结这个内容的人将获得正确的答案勾选标记。例如,创建一个视图控制器子类,它是FirstView.xib的文件所有者,并包含一个保留的IBOutlet,您可以将其链接到同一xib文件中的表视图控制器。


4
第一个单元格加载的原因是由于tableview预先加载了它,就像屏幕上的其他单元格一样。所有单元格都是从数据源方法加载的:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

请确保你已经明确地设置了tableView的delegate和datasource。这可以通过代码或IB完成。方法如下:

[self.tableView setDelegate:self];
[self.tableView setDataSource:self];

正如Bluephlame所说,你可能在某个地方释放了UITableVewController。

为了找出问题所在,在dealloc方法内设置一个断点:

- (void)dealloc{


     //releasing things

     [super dealloc];
} 

如果你发布了它,你会触发这个断点。然后你就可以开始追踪罪犯了。

2

我曾遇到相同问题,解决方法是在数组中添加nil作为最后一项。

出现问题的原因是:

pairs = [[NSArray alloc] initWithObjects:@"EUR/USD",@"USD/JPY",@"GBP/USD",@"USD/CHF",@"USD/CAD"];

但不适用于此:
pairs = [[NSArray alloc] initWithObjects:@"EUR/USD",@"USD/JPY",@"GBP/USD",@"USD/CHF",@"USD/CAD",nil];

希望这可以帮到你。

2

将内存分配给数组,而不是使用[NSArray arrayWithObjects:]。如果没有内存分配,它不会重新加载行...使用array=[NSArray alloc] initWithObjects]代替上述方法。


欢迎来到 Stack Overflow。回答问题时,值得花时间编写完整的句子,并正确获取函数、类等名称,因为提问者通常不知道您是否打错了。 - Malcolm Box

0
我曾经遇到过同样的问题。我在一个nib文件中有一个UITableViewController子类,但是我只声明了UITableView作为一个outlet/property,这导致tableview的UITableViewController在仍在使用时被释放。
快速解决方法就是在File's Owner类中添加一个outlet,引用嵌入的UITableViewController即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接