【发布时间】:2012-09-04 10:21:05
【问题描述】:
我有一个带有谓词的 fetchedResultsController,其中 "isOpen == YES"
当调用 closeCurrentClockSet 时,我将该属性设置为 NO。因此,它不应再出现在我的 tableView 上。
出于某种原因,这不会发生。
有人可以帮我解决这个问题吗?
-(void)closeCurrentClockSet
{
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isOpen == YES"];
NSArray *fetchedObjects =
[self fetchRequestForEntity:@"ClockSet"
withPredicate:predicate
inManagedObjectContext:[myAppDelegate managedObjectContext]];
ClockSet *currentClockSet = (ClockSet *)fetchedObjects.lastObject;
[currentClockSet setIsOpen:[NSNumber numberWithBool:NO]];
}
--
我还有几个方法,使用完全相同的方法, 通过调用自定义 fetchRequestForEntity:withPredicate:inManagedObjectContext 方法。
在这些方法中,当更改属性时,tableView 会正确更新! 但是上面的这个(closeCurrentClockSet),没有!我不知道为什么。
--
我的 fetchedResultsController 实现来自 Apple 的文档。
另外,还有一个细节。如果我将我的应用程序发送到后台。关闭并重新打开,tableView 显示更新!
我已尽力在 stackOverflow 上关注之前的问题。没有运气。我也 NSLogged 这一点。 对象被正确获取。这是正确的。 isOpen 属性 已正确更新为 NO。但由于某种原因,我的 fetchedResultsController 没有更新 tableView。
我确实尝试了几个“锤子”解决方案,例如 reloadData 和调用 performFetch。但这没有用。或者使用它们会有意义......
编辑:从头开始,它确实有效,在我的 resultsController 上的 performFetch 之后立即调用 reloadData 但使用 reloadData 正在敲定解决方案。另外,它会删除所有动画。我希望我的控制器自动更新我的 tableView。
有人可以帮我解决这个问题吗?
非常感谢任何帮助!
谢谢,
努诺
编辑:
完整的实现。
fetchedResultsController 非常标准和简单。其他一切都来自 Apple 的文档
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController) {
return _fetchedResultsController;
}
NSManagedObjectContext * managedObjectContext = [myAppDelegate managedObjectContext];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"ClockPair"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSString *predicate = [NSString stringWithFormat: @"clockSet.isOpen == YES"];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:predicate]];
NSSortDescriptor *sortDescriptor1 =
[[NSSortDescriptor alloc] initWithKey:@"clockIn" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:@"Root"];
_fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
--
Apple 文档中的样板代码:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (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:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id )sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
第一次更新:
Tracking [managedObjectContext hasChanges] 确实返回 YES,这是应该的。但是 fetchedResultsController 不会更新 tableView
第二次更新
didChangeObject:atIndexPath: 对于这种特殊情况,不会被调用! 我还有 2 种方法,使用完全相同的代码,它们只是碰巧是不同的实体。他们完美地工作。感谢@Leonardo 指出这一点
3TH UPDATE这个方法,遵循同样的规则。但确实有效。
- (void)clockOut
{
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isOpen == %@", [NSNumber numberWithBool:YES]];
NSArray * fetchedObjects =
[self fetchRequestForEntity:@"ClockPair"
withPredicate:predicate
inManagedObjectContext:[myAppDelegate managedObjectContext]];
ClockPair *aClockPair = (ClockPair *)fetchedObjects.lastObject;
aClockPair.clockOut = [NSDate date];
aClockPair.isOpen = [NSNumber numberWithBool:NO];
}
有人对我可能遗漏的内容有任何其他想法吗?
谢谢,
努诺
【问题讨论】:
-
设置为 NO 后,您是否尝试保存上下文?我想是的。您是否还尝试查看 _fetchedResultsController 是否仍将控制器作为委托?您是否设置了断点以查看是否输入了 didChangeObject:atIndexPath: ?另外,我不确定这一点,但我认为谓词不应该用字符串构建,而是直接用 [NSPredicate predicateWithFormat:@"isOpen==%@",[NSNumber numberWithBool:NO]]
-
我做到了。它确实保存了应有的上下文,而不会产生任何错误。是的,它仍然存在。对 -> other
-
这是因为您通过关系进行过滤的方式。关系中的数据发生了变化,但 FRC 已经获取了这些对象。为了确认,请发布更改数据库但“工作正常”的其他方法之一的代码。另外,您说您尝试重新加载和重新获取,但没有成功。这很奇怪,所以请发布您为重新加载/重新获取数据所做的工作。
-
刚刚发布了更新 3。我花了一整天的时间...然后你来了!它现在有效......我很难过!非常感谢先生!调用 performFetch 后 reloadData。 "if (![[self fetchedResultsController] performFetch:&error])" 现在可以工作了!但我不得不说,我真的很想在不调用 reloadData 的情况下做到这一点。 reloadData 取出我的动画。你认为没有它我还能做到这一点吗?
-
@JodyHagins 您还说过,“关系中的数据发生了变化,但 FRC 已经获取了这些对象”。我很想明白这一点。它确实获取了对象。但是通过将该属性更改为“否”,它们应该不再出现。因为我的谓词过滤掉了它们。 p.s. ClockSet 有很多 ClockPairs。如果clockSet.isOpen 设置为NO。然后所有clockPairs 应该从我的tableView 中消失。我不需要强制手动 performFetch,重新获取,然后重新加载数据。我应该吗?
标签: objective-c ios nsfetchedresultscontroller nsmanagedobject nsmanagedobjectcontext