【问题标题】:Add extra row to a UITableView managed by NSFetchedResultsController向 NSFetchedResultsController 管理的 UITableView 添加额外的行
【发布时间】:2012-03-25 03:41:39
【问题描述】:

我在我的应用程序中使用UITableViewController 作为表格,并添加了NSFetchedResultsController 以提供要在表格中显示的数据(将self 设置为代表)。

但是我想添加一个唯一的单元格作为表格的最后一个单元格,与NSFetchedResultsController 的谓词产生的项目无关,我希望这个单元格始终位于表格的底部。

我已经尝试在表格视图数据源中简单地为这些方法添加 1:

- (NSUInteger)numberOfSectionsInTableView:(UITableView *)sender
{
    return [[self.fetchedResultsController sections] count] + 1;
}
- (NSUInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSUInteger)section
{
    return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects] + 1;
}

然后捕获这样生成额外行的情况(该表只有 1 个部分):

- (UITableViewCell *)tableView:(UITableView *)sender
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == [self.fetchedResultsController.fetchedObjects count]) {
        //Generate the last cell in  table.
    } else {
        //Generate the rest of the cells like normal.
    }
    return nil; //To keep the compiler happy.
}

这会检查索引是否是最后一个单元格并适当地处理它。

但是我在运行时仍然收到以下错误:

*** Terminating app due to uncaught exception 'NSRangeException', 
reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

知道是什么原因造成的吗?或者有没有更好的方法向由 NSFetchedResultsController 控制的表视图添加额外的行?

【问题讨论】:

    标签: ios ios5 uitableview nsfetchedresultscontroller


    【解决方案1】:

    如果您实现文档中指示的所有数据源方法(更新等),则获取的结果控制器与 tableview 紧密相关。它会变得非常混乱和hacky。

    您的“额外行”可以改为表格的页脚视图吗?这将永远在底部。让它看起来像一个单元格不会做太多的工作,尽管从它的外观来看,无论如何你希望它看起来与其他单元格不同。

    【讨论】:

    • 啊,是的,这实际上是一种更好的实现方式,谢谢。 (显然我对 iOS 编程还是很陌生 :-))
    • 是的,它变得非常 hacky。这个想法既简单又伟大......非常感谢!
    • @BishalGhimire 是的,这就像一百行代码,可能不适用于重新排序、批量更新或大量其他边缘情况。
    【解决方案2】:

    鉴于表格只有一节,这段代码看起来不对:

    - (NSUInteger)numberOfSectionsInTableView:(UITableView *)sender
    {
        return [[self.fetchedResultsController sections] count] + 1;
    }
    

    我怀疑当 tableview 尝试检索第二部分时会发生崩溃; + 1 应该被删除。

    可以使用来自 fetched results controller 的表执行更复杂的操作(请参阅 NSFetchedResultsController prepend a row or section ),因此我确信这个简单的案例可以工作。

    【讨论】:

    • 仍然 tableView:cellForRowAtIndexPath: 将被调用 [[self.fetchedResultsController section] count] 次。
    【解决方案3】:

    为什么不直接使用 UITableView 内置的 Header 和 Footer Views 呢?

    例子:

    UIView *customBottomView = [UIView alloc] init... //set up your View (what you called custom bottom cell)

    self.table.tableFooterView = customBottomView; //或者tableHeaderView

    从技术上讲,您正在添加一个显示在表格下方(或上方)的视图,该视图被添加到表格中并由 TableView 出色地处理。对于用户来说,无法确定这是(最后一个)单元格还是仅仅是一个视图。如果您打算使用类似 didSelectRowAtIndexPath 的方法,您只需要解决问题

    【讨论】:

      【解决方案4】:

      您绝对不想破解索引路径,标题也不会这样做,因为单元格有很多您不想失去的优势。

      所以Apple解决这个问题的方法首先是制作一个超级实体。然后为要添加的行创建另一个新实体,并使其成为子实体。然后使您正在获取的现有行实体也成为子实体。然后将您的 fetch 控制器的 fetch 实体更改为此超级实体,因此它将返回结果中的两个子实体。在超实体中添加一个 sortOrder 属性,并将它设置为 1 在要首先出现的行上,然后在所有其他行上设置为 2,这就是使新行出现在顶部的原因。

      这就是 Apple 在 iOS Notes 应用程序中实现文件夹列表视图的方式。提取控制器的实体是 NoteContainer,2 个子实体是 Account 和 Folder。顶部的“所有 iCloud”行是一个帐户,其余的是文件夹。

      NoteContainer (sortOrder)
      - Account (1)
      - Folder (2)
      

      注意垃圾桶也是一个文件夹,但它的排序顺序为 3,所以它出现在最后。

      这里更广泛的教训是使用 fetch 控制器根据您希望它们在 UI 中的显示方式对实体进行建模,而不是像在规范化关系数据库中那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多