在解除模态呈现的ViewController后,UITableViewCell不会反映更改

时间:2013-02-18 17:48:15

标签: ios uitableview core-data nsfetchedresultscontroller segue

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

所有核对表项都存储在CoreData中。

新的CoreData实体由SecondViewController创建并存储。在点击触发checklist被解雇的按钮之前,用户可以根据需要添加尽可能多的SecondViewController个项目。这里由于这个SecondViewController是模态呈现的,我假设它的活动与FirstUIViewController根本没有任何关系。

在包含FirstViewController的{​​{1}}处,有UITableView再次在CoreData执行获取请求,并将所有数据都提供给NSFetchedResultsController。 NSFetchedResultsController的委托也指向此UITableView

问题在于,在解除FirstUIViewController之后,SecondViewController似乎注意到新核对表实体的插入,并在UITableView中插入了新的UITableView。但是,奇怪的是,这个新插入的行不会显示正确的UITableCell。只显示标签上没有任何内容的空白cell.textlabel

以下是我配置UITableViewCell

的方法
UITableViewCell

以下是我对NSFetchedResultsControllerDelegate

的看法
- (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;    
}

强制- (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,但是tableView仍然没有正确显示新添加的单元格标签。

Reload Data!

我想知道这里可能出现什么问题。以某种方式- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self performFetch]; [self.tableView reloadData]; NSLog(@"Reload Data!"); } self.tableView被解雇后没有重新加载。有什么建议吗?

##已编辑

好的,我在SecondViewController内尝试[self.tableView reloadData]更奇怪。新的tableViewCell仍然没有正确显示其标签;然而,在等待30秒后,标签才会神奇地弹出!这是否意味着我的iPhone / iPhone模拟器需要时间思考?

1 个答案:

答案 0 :(得分: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. 复制&#34;典型用途&#34;以上网站的部分。您不需要实施&#34;用户驱动的更新&#34;。一定要设置

    self.fetchedResultsController.delegate = self;

  3. 如果要检查此代码是否正常工作,可以将breakPoints或NSLog放入controllerWillChangeContentcontroller:didChangeObject

  4. 您不需要在第一次之后再次调用performFetch。此代码适当地侦听更改和更新。
  5. 因为我总是建议每个人 - 我喜欢MagicalRecord - 所以使用它。
  6. 配置单元格

    下面的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];
    }