尝试移动UITableView行时崩溃

我有一些相当复杂的规则在UITableView移动行。 每个部分有不定数量的部分和行,并且基于各种规则,行可以在部分之内或部分之间由用户移动到特定的其他位置。

所有的数据更新和一切工作。 但偶尔,移动一行后,应用程序将假发,突然间将有一个空的空间,应该显示一行。

我在用着:

  - (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath 

指定用户可以根据单元格的位置拖动行的位置。 98%的时间工作。 但是在某些情况下,当用户只允许在部分之间拖动(无法对部分内的行进行重新sorting)时,会出现此错误,那么应用程序在没有行滚动区域后会崩溃。

抛出的exception是相当无用的:

终止由于未捕获的exception'NSRangeException'的应用程序,原因:'*** – [NSCFArray objectAtIndex:]:索引(6)超越边界(6)

我的代码没有在堆栈上。 最后一个UITableView特定的方法是

-[UITableView(UITableViewInternal) _visibleCellForGlobalRow:]

有没有人看到这个问题发生之前? 有任何想法吗?

我只是打我认为是在我的应用程序相同的问题。

情况是我有两个表格部分。 项目可以在部分内部和部分之间拖动。 用户可以将单元格拖动到第一部分中的任何一行,但是在第二部分中,这些项目是sorting的,因此对于任何给定的单元格,只有一个有效的行。

如果我滚动视图,以便第1部分的底部和第2部分的顶部是可见的,请抓住第1部分中sorting到第2部分底部的项目,并将其拖到第2部分的顶部,即我的tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:方法被调用,并返回正确的目标位置,这是位于屏幕底部几行。 在用户界面中,您可以看到在屏幕底部创build了一个空单元格,这不是正确的目标行。

当你放开单元格时,在屏幕底部创build的虚假单元格(在第2部分中间)停留在那里! tableView:cellForRowAtIndexPath:甚至从来没有被调用。 只要你试图用这个单元做任何事情,你就会崩溃。

我的第一个解决scheme是在tableView:moveRowAtIndexPath:toIndexPath:的末尾调用[tableView reloadData]。 但是这会导致崩溃,所以相反,我会在间隔后间接调用它。 但是还有另外一个 bug:在延迟的reloadData调用之后, tableView:moveRowAtIndexPath:toIndexPath:被再次调用,将一个项目移过第一部分的末尾到同一位置。 所以,我不得不添加代码来忽略虚假请求。

所以,这是代码:

 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)pathSrc toIndexPath:(NSIndexPath *)pathDst { // APPLE_BUG: after doing the delayed table reload (see below), we get a bogus // request to move a nonexistant cell to its current location if (pathSrc.row == pathDst.row && pathSrc.section == pathDst.section) return; // update your data model to reflect the move... // APPLE_BUG: if you move a cell to a row that's off-screen (because the destination // has been modified), the bogus cell gets created and eventually will cause a crash [self performSelector:@selector(delayedReloadData:) withObject:tableView afterDelay:0]; } - (void)delayedReloadData:(UITableView *)tableView { Assert(tableView == self.tableView); [tableView reloadData]; } 

请注意,仍然存在一个UI错误。 在屏幕上,拖动的单元格变成虚假空单元格的animation。 在animation的结尾处,空单元格会重新绘制该行的正确数据,但是敏锐的用户会注意到被拖动的单元格正被animation到错误的位置,然后立即变形到不同的单元格。

这绝对是一个愚蠢的用户界面。 我考虑将正确的目标行滚动到屏幕上,但是如果我这样做的话,屏幕将会填满第二部分,然后任何试图拖回第一部分的尝试都会被我的(现在令人讨厌的)自动滚动阻止。 我可能不得不改变用户界面,但这需要对我的数据模型进行一些复杂而烦人的更改。

我有一个类似的错误与删除,我不知道了一段时间 – 但我把[tableView beginUpdates][tableView endUpdates]代码周围,它修复了一切。 可能是因为你的数据源只是在重新绘制之前没有更新,而且这些方法应该防止(值得一试)。

看起来像某个地方正在请求元素6从一个只有索引0-5 (意思是6个元素)的元素的数组。

这通常发生在代码尝试执行时:

 NSUInteger index = [somearray count]; id obj = [somearray objectAtIndex:index]; 

因为count是上边界,数组从0开始,最后一个元素在count - 1

这可能不是直接在你的代码中,但你可能会限制某些元素,然后请求一个过去的最后一个元素。

你正在更新targetIndexPathForMoveFromRowAtIndexPath的表的数据模型

或者在DataSource委托方法中: tableView:moveRowAtIndexPath:toIndexPath:

从表格视图编程指南iPhone OS,重新sorting表单元格:

表视图发送tableView:moveRowAtIndexPath:toIndexPath:到它的数据源(如果它实现了方法)。 在此方法中,数据源更新作为表视图的项目源的数据模型数组,将项移动到数组中的其他位置

而对于委托方法,则写为:

每当拖动的行结束时,表视图发送tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:到它的委托(如果它实现了方法)。 在这种方法中,委托可以拒绝拖动行的当前目标,并指定一个替代的目标。

tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:用于确定是否允许重定位,但对于数据模型的实际更改应发生在tableView:moveRowAtIndexPath:toIndexPath:

也许这就是你在做什么,但是我不能从你提供的信息中知道。

这里Cityarray是一个数组…

  id obj =[Cityarray objectatindex:sourceindexpath.row]; [Cityarray removeObjectatindex:(sourceindexpath.row)]; [Cityarray insertObject:obj atindex:destinationindexpath.row]; 

我在相当一段时间没有访问过这个问题。 我提出的解决scheme是去除复杂的规则。 不知道为什么他们允许使用复杂的规则,如果它使应用程序崩溃的应用程序。 不知道这是否在最新版本的OS中修复。

我只是碰巧见证了这个问题。 但是,我的崩溃版本似乎发生在我试图支持的iOS 3.0设备上,并且表中只有两行正在尝试重新排列。 我用iOS 4.0的另一个设备上的相同的代码再次运行该应用程序,该错误似乎已经修复。

我仍然在研究这个问题,但截至目前,我正在禁用iOS 3.0设备上的行移动,直到find修复程序。