我在这里遇到一种情况并且失去了我的头发......
由核心数据驱动的非常简单的应用程序,其具有带有添加导航按钮的表视图控制器。它与食谱样本非常相似,但存在差异
核心数据部分很好,因为新条目已添加到底层存储并使用获取的结果控制器进行检索。当我添加将放在列表顶部的新项目时,问题就出现了。例如,这可以是空列表上的新项目或具有排序顺序的项目。 放在顶部的项目不可见!单元格在那里,带有nil文本标签,但是,我清楚地看到获取的结果控制器发出了更新通知,我配置了单元格,用新文本更新。
我可以使该单元格显示的唯一方法是滚动数据表以调用cellForRowAtIndexPath
,然后更新项目文本。我添加了另一个项目,它将被放置在顶部,同样新项目文本不可见。我添加了一些将存在于底部的项目 - 没问题,单元格中的文本是可见的。最初,当我刚刚启动应用程序时没有问题,所有项目都可见。
不确定是否有人可以在没有源代码的情况下帮助解决这个问题,但仍然希望得到一些关于如何调试的提示......我试图将委托调用与Receipe应用程序进行比较,并且都是一样的。
UPD:
- (void)configureCell:(UITableViewCell *)cell
atIndexPath:(NSIndexPath *)indexPath
{
Word* word = (Word*)[fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = word.word;
printf("configureCell: %d : \"%s\"\n", indexPath.row,
[word.word cStringUsingEncoding:NSASCIIStringEncoding]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
printf("didChangeObjectAtRow: %d: insert\n", newIndexPath.row);
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
printf("didChangeObjectAtRow: %d : delete\n", indexPath.row);
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
printf("didChangeObjectAtRow: %d / %d : move\n", indexPath.row, newIndexPath.row);
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = [[fetchedResultsController sections] count];
if (count == 0)
{
count = 1;
}
printf("number of sections: %d\n", count);
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0)
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
printf("number of rows in sections: %d is %d\n", section, numberOfRows);
return numberOfRows;
}
- (NSFetchedResultsController*)fetchedResultsController
{
if(fetchedResultsController != nil)
return fetchedResultsController;
// This is autoreleased as the name implies
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Word" inManagedObjectContext:managedObjectContext];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSSortDescriptor* sortByWordDescriptor = [[NSSortDescriptor alloc] initWithKey:@"word" ascending:YES];
NSArray* sortArray = [[NSArray alloc] initWithObjects:sortByWordDescriptor, nil];
[fetchRequest setSortDescriptors:sortArray];
NSFetchedResultsController* controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Hmm"];
controller.delegate = self;
self.fetchedResultsController = controller;
[fetchRequest release];
[sortByWordDescriptor release];
[sortArray release];
[controller release];
return fetchedResultsController;
}
- (void) add:(id)sender
{
WordzWordEditView *wordEditViewController = [[WordzWordEditView alloc] initWithNibName:@"WordzWordEditView" bundle:nil];
wordEditViewController.delegate = self;
Word* word = [NSEntityDescription insertNewObjectForEntityForName:@"Word" inManagedObjectContext:self.managedObjectContext];
wordEditViewController.word = word;
UINavigationController *editWordNavigationController = [[UINavigationController alloc] initWithRootViewController:wordEditViewController];
[self presentModalViewController:editWordNavigationController animated:YES];
[wordEditViewController release];
[editWordNavigationController release];
}
UPD:输出
controllerWillChangeContent
didChangeObjectAtRow: 0: insert
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2
cellForRowAtIndexPath: 0
configureCell: 0 : "(null)"
post configuring: "(null)"
controllerWillChangeContent
configureCell: 0 : "asd"
didChangeObjectAtRow: 0 : update with 'asd'
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2
答案 0 :(得分:1)
我会改变:
case NSFetchedResultsChangeUpdate:
printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
为:
case NSFetchedResultsChangeUpdate:
printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
我不确定为什么配方应用程序会覆盖该行为,因为configureCell仍会被调用。
答案 1 :(得分:1)
您是否在-viewWillAppear:animated中尝试了[self.tableView reloadData]? 第一排我遇到了类似的问题。但是在我添加之后,一切都很好。
答案 2 :(得分:0)
如果没有源代码,很难确定,当您添加数据时,您正在调用
– insertRowsAtIndexPaths:withRowAnimation:
如果您在添加后调用[self.tableview reloadData]
,则会显示
答案 3 :(得分:0)
你投的错误类型。 (复制/粘贴错误)您在UITableViewCell
tableView:cellForRowatIndexPath
case NSFetchedResultsChangeUpdate:
printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
[self configureCell:(RecipeTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
替换:
[self configureCell:(RecipeTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
使用:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
答案 4 :(得分:0)
一些观察结果:
动作方法中的这一行:
Word* word = [NSEntityDescription insertNewObjectForEntityForName:@"Word" inManagedObjectContext:self.managedObjectContext];
...触发器:
case NSFetchedResultsChangeInsert:
printf("didChangeObjectAtRow: %d: insert\n", newIndexPath.row);
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
...在对话框完成之前和Word
managedObject具有其word
属性的值之前。这将创建一个空填充的单元格。
(我在Recipie应用程序中记录了这些方法并得到了:
2010-07-07 18:56:08.848 Recipes[53880:207] NSFetchedResultsChangeInsert:=<NSIndexPath 0x11286a0> 2 indexes [0, 0]
2010-07-07 18:56:22.872 Recipes[53880:207] NSFetchedResultsChangeUpdate=<NSIndexPath 0x11286a0> 2 indexes [0, 0]
......按顺序。)
有趣的是,您没有记录NSFetchedResultsChangeInsert
。这让我觉得缺少了一些东西。可能在您的日志记录中。
我认为问题可能实际上是由于使用用于更改Word.word值的模态控制器引起的。模式表示会阻止表在发生时响应NSFetchedResultsChangeUpdate
,因此它保持初始空值,直到您滚动导致它从获取的结果控制器重新加载单元格。只是一个猜测。
您可以通过插入Word对象然后在没有模态视图的情况下更改代码中的word属性来进行测试。也许使用计时器给一点延迟。如果这样可行,那么它肯定是导致问题的模态视图。
如果不是,我认为你应该注意记录整个索引路径对象,以确保你没有一些部分的古怪。
答案 5 :(得分:0)
我遇到了类似的问题,并开始寻找解决方案并遇到了这个老帖子。我没有看到问题已经解决,所以我看了一下方法中调用的内容
当您从详细控制器返回时,它实际上正在执行更新,而不是执行插入操作。这与核心数据配方应用程序执行创建添加到数据库的项目的顺序有关 - 在调用详细信息控制器之前。
通过在NSFetchedResultsChangeUpdate中添加以下行,我能够显示第一行
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];