我有一个带有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模拟器需要时间思考?
答案 0 :(得分:2)
<强>解释强>
您的核心数据保存需要时间。如果要保存数据,然后立即关闭模态视图控制器,则performFetch
函数上存在竞争条件。这就是为什么你会发现它在viewWillAppear
函数中不起作用的原因,但是当你按下按钮时它会起作用。它有时可以在viewDidAppear中工作,但不能保证。这取决于您是否使用模拟器,以及系统的繁忙程度。
具体建议
由于您从核心数据中提取数据,我建议您使用NSFetchedResultsController
并实施NSFetchedResultsControllerDelegate
。这些是专门为将coreData绑定到UITableViewController而设计的。它会侦听更改并根据这些更改立即添加,删除或更新行。
使用代码更新
要正确实施NSFetchedResultsControllerDelegate
,您只需从此网站复制代码:http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html
一些提示:
cellForRowAtIndexPath
的方式稍作修改。创建一个名为configureCell
的新方法。它是一个很好的模式,所以你可以在Apple和其他地方的许多示例代码中找到它。 复制&#34;典型用途&#34;以上网站的部分。您不需要实施&#34;用户驱动的更新&#34;。一定要设置
self.fetchedResultsController.delegate = self;
如果要检查此代码是否正常工作,可以将breakPoints或NSLog放入controllerWillChangeContent
或controller:didChangeObject
。
配置单元格
下面的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];
}