[英]NSInternalInconsistencyException when last row is removed from the section
[英]Strange animation when moving last row out of section and deleting section
我有一个多部分的tableview。 在编辑模式下,我允许将行从一个部分移到另一部分。 将最后一行从一个部分中删除后,我将删除该部分。 所以我在moveRowAtIndexPath内部使用deleteSection。
当最后一个项目从节中移出时,节标题将按计划消失。 但是有一个非常奇怪的动画错误,其中移动的行似乎与它上方的行“合并”,并且在“ to”部分的底部显示一个空行(可能是因为该部分的numberOfRows为正确,但2行位于同一位置)。 甚至更陌生,当我单击该行的重新排序控件(不移动项目,只需触摸并释放)时,两个项目“合并”。
我发布了一个视频来演示这一点。
我尝试包装我的数据更改并在开始/结束更新中查看更改,但无济于事。
我已经在这里上传了一个测试项目,我还将在下面发布代码。 要点:
代码(所有这些都在演示项目中):
我在loadView中设置了数组:
- (void)loadView{
array1 = [NSMutableArray array];
[array1 addObject:@"test 0"];
[array1 addObject:@"test 1"];
[array1 addObject:@"test 2"];
array2 = [NSMutableArray array];
[array2 addObject:@"test a"];
[array2 addObject:@"test b"];
[super loadView];
}
我也有一个返回这些数组组合的方法-用作数据源:
- (NSMutableArray *)sourceArray{
NSMutableArray *result = [NSMutableArray array];
if (array1.count > 0) {
[result addObject:array1];
}
if (array2.count >0) {
[result addObject:array2];
}
return result;
}
这使得行/节的数量非常简单:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return self.sourceArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[self.sourceArray objectAtIndex:section] count];
}
标准单元格/标题格式:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [[self.sourceArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:@"Section %i", section];
}
这是我做魔术的地方
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
我注意到,来自待删除部分的行将消失,直到您修改订单控件。
我怀疑当tableview调用此数据源方法时,它的状态仍处于执行移动的中间,因此调用'deleteSections'将使表尝试删除正在移动的行。 它并没有太大的合并,因为它以与节标题相同的速率逐渐消失,而它下面的那个只是在回弹以填充空间。
轻击控件会使表视图重新调整自身位置,并意识到该行实际上并未消失。
要尝试解决此问题,请尝试通过调度调用在下一个runloop中运行删除操作,例如:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
dispatch_async(dispatch_get_main_queue(), ^() {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
});
}
这将导致删除操作仍在主线程上运行,但允许'moveRow'及其碰巧发生的任何调用栈在删除调用之前完成其逻辑
您的问题出在动画上。 一个正在完成而另一个尚未完成(移动和删除动画),导致一个单元格被绘制在另一个单元格上。 您可以通过再次移动单元格来验证这一点。 然后将显示正确的顺序。 根据Apple在UITableView上的文档 :
注意:数据源不应在tableView:commitEditingStyle:forRowAtIndexPath:的实现中调用setEditing:animated:。 如果出于某种原因,它必须在延迟后通过使用performSelector:withObject:afterDelay:方法来调用它。
因此,要解决此问题,请对您的代码执行以下操作:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(someMethod:) withObject:fromIndexPath afterDelay:1.0];
}
- (void) someMethod:(NSIndexPath *) fromIndexPath {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
应该工作正常。 只需将延迟更改为更适合您的时间即可。
我认为UITableViewRowAnimationFade动画会干扰UITableViewCell移动动画。 您可以尝试做的一件事是延迟部分删除,以使单元格移动行动画完成。
尝试用以下代码替换您的代码。
-(void)deleteSection:(NSIndexSet*)indexSet
{
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(deleteSection:) withObject:[NSIndexSet indexSetWithIndex:fromIndexPath.section] afterDelay:1.0];
// [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
在最后一行丢失动画的解决方案:
if([listOfItemsOnTransaction count]==indexPath.row){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
}
如果行或行中的内容可以引起焦点,您是否检查过是否调用过resignFirstResponder
或[view endEditing:YES]
? 我们在使用文本字段时看到了这一点,并且(IIRC也依赖于iOS 4版本)将焦点放在其中一个字段上。
删除该部分后,您必须重新加载tableview。 试试这个代码。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
在代码中交换fromArray
和toArray
的顺序。 如果该项目从数组中取出具有现有的1一个保留计数,它将具有其添加到之前一个保留的0计数toArray
。
如果您交换订单,则该项目将从保留计数1变为2,然后在删除完成后返回1。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.