Ios NSFetchedResultsController预先添加行或节

Ios NSFetchedResultsController预先添加行或节,ios,uitableview,nsfetchedresultscontroller,nsindexpath,Ios,Uitableview,Nsfetchedresultscontroller,Nsindexpath,我有一个UITableView,其中填充了标准的NSFetchedResultsController。然而,我想预先准备一行或一节(最好是一行,但两者都可以很好地工作。) 我现在看到的唯一方法是,在处理处理来自NSFetchedResultsController的数据的节/行时,手动重写所有NSIndexPath,以诱使它看到索引0处的节,并从索引0处的行开始。然而,这似乎是一个非常糟糕的想法,会很快变得混乱,所以我希望避免这种情况 这方面的一个很好的例子是,当你第一次启动官方Twitter应用

我有一个UITableView,其中填充了标准的NSFetchedResultsController。然而,我想预先准备一行或一节(最好是一行,但两者都可以很好地工作。)

我现在看到的唯一方法是,在处理处理来自NSFetchedResultsController的数据的节/行时,手动重写所有NSIndexPath,以诱使它看到索引0处的节,并从索引0处的行开始。然而,这似乎是一个非常糟糕的想法,会很快变得混乱,所以我希望避免这种情况

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


红色部分几乎就是我想要实现的,而黄色部分我假设是同一部分中NSFetchedResultsController的结果(尽管其自定义样式可能是一个单独的部分)。

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

另一个解决方案不必非常复杂,就会变得更加麻烦


话虽如此,您提议的“标题”似乎确实是节标题的典型候选

这可以用一种相当干净的方式来实现

我假设您从使用标准NSFetchResultsController(使用Apple的示例代码)设置的标准tableview开始

首先,您需要两个实用程序函数:

- (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;
}
这些应该是不言自明的——它们只是帮助我们在需要使用“获取结果”控制器的索引路径访问表时添加额外的行,或者在使用其他方法时删除额外的行

然后我们需要创建额外的单元格:

- (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;
}
确保正确配置它(configurecell将仅对来自fetch results controller的单元格进行调用):

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

// 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 ...>
}
- (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 ...

这是一个公平的观点,我只是在检查NSFetchedResultsController上是否有我不知道的方法,该方法允许您在返回的结果中预加或附加一组行,以便您可以自定义它们。如果在这种方法中,我喜欢动态删除第一行,则可能重复。@Cocoanob是的,那很好。只要正确映射indexPath,基本上可以做任何事情。是的,我尝试了它而不是使用1,我使用的是实例变量。一个非常好和清晰的方法。感谢您分享您的解决方案@JosepH。对于使用瞬态属性作为
sectionNameKeyPath:
参数的fetchedResultsController,这种方法是否可能不起作用?我看到我的tableView在第0节中包含2行(第一行是手动添加的),在第1节中包含4行;如果从节0中删除1行,则会出现以下非常奇怪的错误:更新无效:节0中的行数无效。更新(5)后现有节中包含的行数必须等于更新(4)前该节中包含的行数加上或减去行数。。。。。。从该节插入或删除(插入0,删除0),并加上或减去移入或移出该节的行数(移入0,移出0)。fetchedResultsController认为我在第0节中有5个对象,而不是在tableView中看到的第0节中的1+4节中的1,这一事实使我认为这种方法不适用于sectionNameKeyPath生成的节。我说得对吗?
- (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 ...