在iOS 6/7中,“表格单元没有被重用的索引path”消息的含义是什么?

自从开始编译我的应用程序与iOS 6(也从iOS 7),我已经开始看到这个消息。 我知道UITableViewspipe理单元格的方式在iOS 6中是不同的,但是我不需要修改我的代码来继续工作。 但是我担心这个消息可能会指出一些我还没有看到的潜在问题。 任何人都可以摆脱任何光?

我开始从iOS 7 beta 5以后的版本中看到这个错误,包括在iOS 7 GM / Release版本中,而在iOS 6或早期的iOS 7 beta版本中,我的应用程序从来没有发生过这种错误。 经过大量的实验,我find了原因:

我使用UITableViewCell对象作为我的节标题视图,并在tableView:viewForHeaderInSection:返回它们。 这似乎是常见的做法,尤其是在iOS 5中,当使用Interface Builder将故事板视图devise为原型表格视图单元格变得容易时更是如此。

当我改变我的应用程序只使用常规的UIView子类为我的部分标题视图,错误消失了,更重要的是,我的表视图停止随机删除部分标题!

看起来(从iOS 7 beta 5开始) UITableView在内部维护所有UITableViewCell对象在其视图层次结构中的映射以及它们各自的索引path。 由于页眉节段(或页脚的表格视图页眉)没有索引path,所以如果你为这些视图使用UITableViewCell对象,那么当表格视图发现一个UITableViewCell没有索引path,导致“表格单元格没有索引path被重用”的错误,如果你不走运,在你的表格视图中显示毛刺:

更新 :如果你有权访问苹果开发者论坛,这里是关于它的线程(我开始): https : //devforums.apple.com/message/882042#882042

正如在该线程中所build议的那样,如果您不想重新考虑因素,则可以在UITableViewCell周围创build一个UIView包装器,并将其作为节标题视图返回。

 UIView *view = [[UIView alloc] initWithFrame:[cell frame]]; [view addSubview:cell]; return view; 

但是请注意,这个“包装” UIView方法不能很好地与AutoLayout和设备旋转,所以我build议你使用一个UIView子类头和页脚单元格,而不是一个UITableViewCell子类,在答案的主要部分中解释。

我会返回UITableViewCell的contentView,而不是创build一个包装器。在storybord中固定的约束jabble

 return cell.contentView; 

我遇到了同样的问题,花了我几个小时才find问题。 原来我在设置单元格时调用了[textField becomeFirstResponder] (这里的textField是自定义tableviewcell的一部分)。 [textField becomeFirstResponder]轮stream发布keyboardWillShow通知,这反过来又导致tableview过早地加载自己,从而导致臭名昭着的“ 表索引没有索引path被重用 ”消息,一旦我删除了这个调用,问题就消失了。

除了被接受的答案(mluisbrown)之外,我还需要在头部单元格中添加一个autoresizingMask,因为我的包含一个多行标签,即

 UIView *view = [[UIView alloc] initWithFrame:[cell frame]]; cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; [view addSubview:cell]; return view; 

这是一个内部的UIKit错误 – 正如苹果自己的开发论坛中提到的那样。 它应该是固定在更新版本的Xcode,虽然我无法find有关哪个版本修复此信息。

除了我以前的文章(我提到这显然是一个UIKit的bug)之外,我能够find一个解决scheme,针对我的特定情况(消息与表中的一些奇怪的可视化故障有关)。

显然,我的自定义单元格被重写-(void)setEditing:animated:花了太长时间才能返回。

我以前的代码是:

 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; [self someAdditionalCode]; } 

我能够解决它通过更改为:

 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; // DRM: we want to perform the actions from this block in the main thread, but // asynchronously to avoid excessive delays which were causing issues. // dispatch_async(dispatch_get_main_queue(), ^void() { [self someAdditionalCode]; }); } 

resignfirstresponder之后做endupdates解决了我的问题(在我的自定义单元格中有一个UITextFIeld)

 -(void)textfieldEditDone { .... [textField resignFirstResponder]; [self.tableView endUpdates]; 

我遇到了与出现的错误信息相同的问题。 据我可以看到,它是由作为其委托协议的一部分从文本字段调用的函数重新加载表视图引起的。 即textFieldDidEndEditing – > [controller.tableview reload …]

为了logging,我在iOS 6下运行时也遇到了这个消息。看起来有些代码是inheritance的或者是导入的,就像这样:

 (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { NSInteger rows = 0; if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) { rows = [delegate numberOfItemsInSection:section]; [tableView beginUpdates]; [tableView endUpdates]; } } 

当beginUpdate:/ endUpdate:序列被删除时,问题就神奇地消失了。

这显然是一个老问题,但希望这可以帮助任何仍然在iOS8 +中遇到这个问题的人,因为这仍然是这个特定错误信息出现的最大问题。

我正在使用PINRemoteImageasynchronous下载图像到一个UIImageView的自定义UITableViewCell内。

为了正确调整行的大小(dynamic高度单元格使用自动布局),一旦图像已经加载,我打电话给:

 self.tableView beginUpdates; self.tableView endUpdates; 

然后我得到了“没有索引path的表格单元被重用”的消息和应用程序崩溃。 我曾经以为PINRemoteImageManagerResult块在主线程上,但是事实certificate它不是 – 因此确保在主线程上调用了开始/结束更新来解决问题。

 dispatch_async(dispatch_get_main_queue(), ^(void){ [self.tableView beginUpdates]; [self.tableView endUpdates]; }); 

那么,我只是用了一天中最好的一部分来解决这个问题,所以希望这个替代解释可以节省一些人的时间。

我有一个桌面视图, 有时这个消息,加载时。 事实certificate,这是由加载视图时触发核心数据对象的KVO通知造成的。 (在观察一个变化的时候,我的控制器在桌面视图上试图调用reloadData,通过在视图加载完成之前不观察对象来进行修复(以前我通过访问器分配了对象之后开始观察对象)

TLDR:检查您是否尝试从主线程以外的地方重新加载数据。

也许这有助于某人:我刷新单个表格视图单元格时,曾经有这个错误。 我打算做一些像

 NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2]; [self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow] withRowAnimation:UITableViewRowAnimationFade]; 

但是不小心,我input了

 NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2]; 

注意两个indexpath的区别:一个是用indexPathForItem (错误)创build的,另一个是用indexPathForRow (正确)创build的。 这一切都导致了tableView和标题中的错误消息的非常奇怪的行为。

这似乎是我的问题是当我试图更新在一个Web调用的callback代码的一部分内的UI触发。 我解决了迫使UI更新发生在主线程上。 我使用这样的代码。

 void runOnMainQueueWithoutDeadlocking(void (^block)(void)){ if ([NSThread isMainThread]) { block(); } else { dispatch_sync(dispatch_get_main_queue(), block); } } 

我在我的后台web调用的成功块内部如下所示。

 runOnMainQueueWithoutDeadlocking(^{ [self.tableView beginUpdates]; [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; }); 

还有一个条件

这发生的时候,不想要一个头,我返回nil

固定:

 func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return "" }