2

我有一个带有 TableView 的 UIViewController 用于显示“清单”项目。这个 ViewController 还有一个按钮,可以触发 segue 以模态方式呈现另一个 UIViewController,供用户添加新的清单项。

所有清单项目都存储在 CoreData 中。

新的 CoreData 实体由SecondViewController. 用户可以checklist在点击触发解除SecondViewController. 在这里,由于这SecondViewController是模态呈现的,我假设它的活动与 根本没有任何关系FirstUIViewController

FirstViewController包含的 中UITableView,有一个NSFetchedResultsController再次在 CoreData 执行获取请求并将所有数据提供给UITableView. NSFetchedResultsController 的委托也指向 this FirstUIViewController

问题是,在解除 后SecondViewControllerUITableView似乎注意到新清单实体的插入,并UITableCell在 UITableView 中插入了新实体。然而,奇怪的是,这个新插入的行没有显示正确的cell.textlabel. UITableViewCell仅显示标签上没有任何内容的空白。

下面是我如何配置UITableViewCell.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ChecklistCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    ChecklistItem *item = [self.fetch_controller objectAtIndexPath:indexPath];
    cell.textLabel.text = item.name;    
}

这是我为 NSFetchedResultsControllerDelegate 提供的

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
    switch (type) {
        case NSFetchedResultsChangeInsert:
            NSLog(@"*** controllerDidChangeObject - NSFetchedResultsChangeInsert");
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

强迫[self.tableView reloadData]似乎有帮助。我知道这一点是因为我添加了一个按钮来调用此方法,并且单元格的标签相应地被刷新和更新。

因此,我尝试了这个,因为我希望它会在解雇后被调用SecondViewController。但是,该方法被调用,因为已Reload Data!记录,但不知何故 tableView 仍然没有正确显示新添加的单元格的标签。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self performFetch];
    [self.tableView reloadData];
    NSLog(@"Reload Data!");
}

我想知道这里可能有什么问题。不知何故,self.tableView在解雇SecondViewController. 有什么建议么?

##已编辑

OK,更奇怪的是我[self.tableView reloadData]在里面试过- (void)viewDidAppear:(BOOL)animated。新的 tableViewCell 仍然不能正确显示它的标签;然而,在等待 30 秒后,标签就神奇地弹出了!这是否意味着我的 iPhone/iPhone 模拟器需要时间思考?

4

1 回答 1

2

解释

您的核心数据保存需要时间。如果您正在保存数据,然后立即关闭模态视图控制器,则该performFetch函数存在竞争条件。这就是为什么您看到它在viewWillAppear函数中不起作用,但在您按下按钮时它起作用。它有时会在 viewDidAppear 中工作,但不能保证。这取决于您是否使用模拟器,以及系统的繁忙程度。

具体建议

由于您是从核心数据中提取数据,我建议您使用NSFetchedResultsController并实现NSFetchedResultsControllerDelegate. 这些是专门为将 coreData 绑定到 UITableViewController 而设计的。它侦听更改并根据这些更改立即添加、删除或更新行。

更新代码

要正确实施NSFetchedResultsControllerDelegate,您只需从该网站复制代码:http: //developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html

一些提示:

  1. 您需要对实施方式稍作更改cellForRowAtIndexPath。创建一个名为configureCell. 这是一个很旧的模式,因此您可以在 Apple 和其他地方的许多示例代码中找到它。
  2. 从上面网站的“典型用途”部分复制代码。您不需要实施“用户驱动的更新”。一定要设置

    self.fetchedResultsController.delegate = self;

  3. 如果你想检查这段代码是否正常工作,你可以将 breakPoints 或 NSLogs 放入controllerWillChangeContentorcontroller:didChangeObject中。

  4. 在第一次之后,您无需再次调用 performFetch。此代码适当地侦听更改和更新。
  5. 正如我一直建议大家——我喜欢 MagicalRecord——所以使用它。

配置单元

下面的 configureCell:atIndexPath 方法由 NSFetchedResultsController 委托调用。

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    Product *product = [_fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = product.name;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Product Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

请参阅此处的委托实现代码。查看对象更新时如何调用 configureCell。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                          withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                          withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
                    atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
于 2013-02-18T18:38:30.563 回答