NSFetchedResultsController预先添加一行或一部分

我有一个UITableView填充一个标准的NSFetchedResultsController。 不过,我想预先安排一个行或一个部分(最好行,但要么真的工作得很好)。

我现在可能看到的唯一方法就是在处理NSFetchedResultsController中的数据的部分/行时,手动重写所有的NSIndexPath,以诱使它看到索引0处的部分,并以索引0处的行开始。似乎是一个非常糟糕的想法,很快就会让人困惑,所以我想避免这种情况。

一个很好的例子就是在官方的Twitter应用程序中,当你第一次启动时,我会引导你添加朋友列表中的一些人。

Twitter应用程序建议页面的屏幕截图,其中突出显示了相关部分

红色部分几乎是我想要实现的,而我假定的黄色部分是来自同一节中的NSFetchedResultsController的结果(尽pipe它们的自定义样式可能是单独的部分)。

这可以做一个相当干净的方式。

我假设你开始与一个标准的NSFetchResultsController使用苹果的示例代码设置的tableview。

首先你需要两个实用function:

- (NSIndexPath *)mapIndexPathFromFetchResultsController:(NSIndexPath *)indexPath { if (indexPath.section == 0) indexPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]; return indexPath; } - (NSIndexPath *)mapIndexPathToFetchResultsController:(NSIndexPath *)indexPath { if (indexPath.section == 0) indexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section]; return indexPath; } 

这些应该是相当自我解释的 – 他们只是帮助我们处理添加额外的行,当我们想要使用从获取的结果控制器的索引path来访问表,或者以另一种方式去除它。

那么我们需要创build额外的单元格:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"MyCellId"; if (indexPath.section == 0 && indexPath.row == 0) { UITableViewCell *cell; cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleGray; cell.textLabel.text = NSLocalizedString(@"Extra cell text", nil); return cell; } UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; } [self configureCell:cell atIndexPath:indexPath]; return cell; } 

确保我们正确configuration它(configuration单元将只从来自提取结果控制器的单元中调用):

 // the indexPath parameter here is the one for the table; ie. it's offset from the fetched result controller's indexes - (void)configureCell:(SyncListViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { indexPath = [self mapIndexPathToFetchResultsController:indexPath]; id *obj = [fetchedResultsController objectAtIndexPath:indexPath]; <... perform normal cell setup ...> } 

并告诉tableview它存在:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger numberOfRows = 0; if ([[fetchedResultsController sections] count] > 0) { id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; numberOfRows = [sectionInfo numberOfObjects]; } if (section == 0) numberOfRows++; return numberOfRows; } 

并回应select:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (indexPath.section == 0 && indexPath.row == 0) { [self doExtraAction]; return; } ... deal with selection for other cells ... 

然后重新映射我们从结果控制器获得的任何更新:

 - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { UITableView *tableView = self.tableView; indexPath = [self mapIndexPathFromFetchResultsController:indexPath]; newIndexPath = [self mapIndexPathFromFetchResultsController:newIndexPath]; switch(type) { ... handle as normal ... 

我理解你对复杂性的担忧,但实际上只是将numberOfRowsInSection:加1 numberOfRowsInSection:并将cellForRowAtIndexPath: indexPath.row加1(除了添加第0行的代码之外)。

另一个解决scheme不需要非常复杂,变得更加麻烦。

这就是说,你提出的“标题”看起来好像是一个标题的典型候选人。