UITableViewCell header 使用 NSManagedContextDidSaveNotification 实现的 NSFetchedResultsController 委托显示绘图问题
UITableViewCell header display drawing issue with NSFetchedResultsController delegate using NSManagedContextDidSaveNotification implementation
我已经使用 NSManagedContextDidSaveNotification
实施了一个 NSFetchedResultsController
委托,以从连接到公共 NSPersistentStoreCoordinator
的另一个 NSManagedObjectContext
推送托管的 objects 更改。
第一次批量导入托管objects时,调用NSFetchedResultsControllerDelegate
方法后,单元格绘图的结果包含如下所示的部分:
这基本上是一个 display/drawing 错误,其中 header 部分被绘制到单元格中。 header 和 cell 是实际有效的 header 和出现在更下方的 cell。
它只会在第一次管理时发生 objects 是批量创建的。如果我重新启动应用程序并且管理的 objects 已经导入,控制器显示一切正常,所以它可能与导入过程有关,这只是典型的 NSFetchedResultsControllerDelegate
实现(粘贴在下面):
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[_tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:
(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[_tableView insertSections:
[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade]; break;
case NSFetchedResultsChangeDelete:
[_tableView deleteSections:
[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade]; break;
case NSFetchedResultsChangeUpdate:
NSLog(@"change section"); break;
case NSFetchedResultsChangeMove:
NSLog(@"move setion"); break;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject atIndexPath:
(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
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];
NSLog(@"change object"); break;
case NSFetchedResultsChangeMove:
[_tableView deleteRowsAtIndexPaths:
[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[_tableView insertRowsAtIndexPaths:
[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"move object"); break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[_tableView endUpdates];
}
问题是我尝试通过检测何时是第一批导入并调用它们来使用 needsLayout
和 reloadData
实现刷新并不能解决此显示问题。哈普!
编辑:
- (void)setupFetchedResultsController {
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Object"];
NSSortDescriptor *sd1 = [NSSortDescriptor sortDescriptorWithKey:@"attribute" ascending:YES];
NSSortDescriptor *sd2 = [NSSortDescriptor sortDescriptorWithKey:@"attribute2" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.relationship.attribute3 == true"];
[fr setPredicate:predicate];
[fr setSortDescriptors:@[sd1, sd2]];
_frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fr managedObjectContext:_moc sectionNameKeyPath:@"attribute" cacheName:nil];
[_frc setDelegate:self];
NSError *error; if (![_frc performFetch:&error]) NSLog(@"%@", error.description);
}
编辑:这是解决问题的代码:
- (void)subscribeToNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeManagedObject:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
}
- (void)mergeManagedObject:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
// This block needed to be sent on the main thread!
[_managedObjectContext
mergeChangesFromContextDidSaveNotification:notification];
});
}
尝试使用 reloadData
解决方案时,您可以先 nil
取出获取的结果控制器,然后延迟重新创建它。然后它应该从头开始正确重建所有内容。
此外,您应该在 结束 table 视图更新后消除高度操作 。在极少数情况下,您必须手动调整 table 视图的内容高度 - 您认为为什么必须在此处进行调整?
此外,您应该检查控制器中所有会影响单元格和部分高度的方法。
您是否尝试过 implementing/adjusting 您的代码如下?
- 当
NSFetchedResultsChangeUpdate
部分发生变化时调用 - reloadSections:withRowAnimation:
,
- moveSection:toSection:
当 NSFetchedResultsChangeMove
发生在部分更改时,
- moveRowAtIndexPath:toIndexPath:
当 NSFetchedResultsChangeMove
在 controller:didChangeObject:
上触发时,
- reloadRowsAtIndexPaths:withRowAnimation:
当 NSFetchedResultsChangeUpdate
在 controller:didChangeObject:
上触发时。
如果这没有帮助,请进入这些方法并查看调用它们的线程。通常,在主线程以外的线程上调用视图更新时会发生视图错误。
最后,您尝试使用 childContexts 了吗?
我已经使用 NSManagedContextDidSaveNotification
实施了一个 NSFetchedResultsController
委托,以从连接到公共 NSPersistentStoreCoordinator
的另一个 NSManagedObjectContext
推送托管的 objects 更改。
第一次批量导入托管objects时,调用NSFetchedResultsControllerDelegate
方法后,单元格绘图的结果包含如下所示的部分:
这基本上是一个 display/drawing 错误,其中 header 部分被绘制到单元格中。 header 和 cell 是实际有效的 header 和出现在更下方的 cell。
它只会在第一次管理时发生 objects 是批量创建的。如果我重新启动应用程序并且管理的 objects 已经导入,控制器显示一切正常,所以它可能与导入过程有关,这只是典型的 NSFetchedResultsControllerDelegate
实现(粘贴在下面):
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[_tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:
(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[_tableView insertSections:
[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade]; break;
case NSFetchedResultsChangeDelete:
[_tableView deleteSections:
[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade]; break;
case NSFetchedResultsChangeUpdate:
NSLog(@"change section"); break;
case NSFetchedResultsChangeMove:
NSLog(@"move setion"); break;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject atIndexPath:
(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
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];
NSLog(@"change object"); break;
case NSFetchedResultsChangeMove:
[_tableView deleteRowsAtIndexPaths:
[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[_tableView insertRowsAtIndexPaths:
[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"move object"); break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[_tableView endUpdates];
}
问题是我尝试通过检测何时是第一批导入并调用它们来使用 needsLayout
和 reloadData
实现刷新并不能解决此显示问题。哈普!
编辑:
- (void)setupFetchedResultsController {
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Object"];
NSSortDescriptor *sd1 = [NSSortDescriptor sortDescriptorWithKey:@"attribute" ascending:YES];
NSSortDescriptor *sd2 = [NSSortDescriptor sortDescriptorWithKey:@"attribute2" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.relationship.attribute3 == true"];
[fr setPredicate:predicate];
[fr setSortDescriptors:@[sd1, sd2]];
_frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fr managedObjectContext:_moc sectionNameKeyPath:@"attribute" cacheName:nil];
[_frc setDelegate:self];
NSError *error; if (![_frc performFetch:&error]) NSLog(@"%@", error.description);
}
编辑:这是解决问题的代码:
- (void)subscribeToNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeManagedObject:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
}
- (void)mergeManagedObject:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
// This block needed to be sent on the main thread!
[_managedObjectContext
mergeChangesFromContextDidSaveNotification:notification];
});
}
尝试使用 reloadData
解决方案时,您可以先 nil
取出获取的结果控制器,然后延迟重新创建它。然后它应该从头开始正确重建所有内容。
此外,您应该在 结束 table 视图更新后消除高度操作 。在极少数情况下,您必须手动调整 table 视图的内容高度 - 您认为为什么必须在此处进行调整?
此外,您应该检查控制器中所有会影响单元格和部分高度的方法。
您是否尝试过 implementing/adjusting 您的代码如下?
- 当
NSFetchedResultsChangeUpdate
部分发生变化时调用- reloadSections:withRowAnimation:
, - moveSection:toSection:
当NSFetchedResultsChangeMove
发生在部分更改时,- moveRowAtIndexPath:toIndexPath:
当NSFetchedResultsChangeMove
在controller:didChangeObject:
上触发时,- reloadRowsAtIndexPaths:withRowAnimation:
当NSFetchedResultsChangeUpdate
在controller:didChangeObject:
上触发时。
如果这没有帮助,请进入这些方法并查看调用它们的线程。通常,在主线程以外的线程上调用视图更新时会发生视图错误。
最后,您尝试使用 childContexts 了吗?