gpt4 book ai didi

iPhone:带有委托(delegate)的 NSFetchedResultsController 和来自单独线程的数据更新

转载 作者:行者123 更新时间:2023-12-03 18:52:22 26 4
gpt4 key购买 nike

首先,很抱歉问题太长。

我知道这里很少有问题讨论类似的问题,但这些问题都没有讨论带有委托(delegate)的 NSFetchedResultsController 以及单独线程中的更新。所有解决方案都没有帮助我。
这些是现有的问题:

现在谈谈我的问题:

  • 我有一个单独的线程,用于从网络更新核心数据对象(使用套接字)。
  • 很少有 View Controller 可以显示来自同一核心数据对象的数据(每个选项卡都包含一个显示其过滤数据的 View Controller )。
  • 每个 View Controller 都有自己的 NSFetchedResultsController 实例,并且委托(delegate)设置为 self。

有时,我会在单独线程中更新数据时收到 was mutated while being enumerated 异常,有时会导致应用程序崩溃。

我做了很多代码操作来尝试修复它,但似乎没有任何帮助。
我尝试不直接从 TableView 数据源方法使用托管对象。相反,我创建了一个包含字典列表的数组。我在上面的 didChangeObject 方法中填充了这些字典。这样我就根本不会接触 View Controller 中的托管对象。

然后我了解到问题出在 NSFetchedResultsController 中,它可能一直在迭代数据。这是与我在单独线程中的数据更新冲突的对象。

问题是,一旦我有了带有委托(delegate)的 NSFetchedResultsController (意味着它“监视”数据并始终更新延迟),如何更新单独线程中的核心数据对象。

NSFetchedResultsControllerDelegate 实现:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if ( self.tabBarController.selectedIndex == 0 ) {
UITableView *tableView = self.tableView;
@try {
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
@catch (NSException * e) {
NSLog(@"Exception in didChangeObject: %@", e);
}
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
if ( self.tabBarController.selectedIndex == 0 ) {
@try {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
@catch (NSException * e) {
NSLog(@"Exception in didChangeSection: %@", e);
}
}
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}

在 TableView 数据源方法中,我直接使用托管对象。

最佳答案

这里有两个单独的问题。首先,如果您遇到变异错误,则意味着您在迭代该集合/数组/关系时正在变异集合或数组(或关系)。找到你在哪里这样做并停止这样做。这是唯一的解决方案。

至于你的更新。您的背景 NSManagedObjectContext 应定期保存。你的主线程应该监听 NSManagedObjectContextDidSaveNotification ,当它收到一个通知时,它会调用主线程上的主 NSManagedObjectContext (因为通知很可能会通过 -mergeChangesFromContextDidSaveNotification: 进入后台线程,它以 NSNotification 作为参数。这将导致所有 NSFetchedResultController 实例触发其委托(delegate)方法。

就这么简单。

更新

ank you for your reply. The exception is thrown on updating the NSManagedObjectContext in the background thread. I use the same NSManagedObjectContext in both threads. The app should be as close as possible to real time app - the updates constantly and the tables should be updated immediately. I don't save at all - I only update the NSManagedObjectContext. I have seen in one of the questions mentioned that someone used to separate instances of NSManagedObjectContext but he still receive the same exceptions once he merges the changes. So, you suggest using 2 separate NSManagedObjectContext's?

首先,从 Apple 的文档(或我的书:)中阅读 Core Data 中的多线程。

第二,是的,每个线程应该有一个上下文,这是核心数据和多线程的黄金规则之一(另一个是不要跨线程传递 NSManagedObject 实例)。这可能是您崩溃的根源,如果不是,它将成为将来崩溃的根源。

更新

I have tons of data and I update only the modified/new/deleted items in the table. If I will start saving then will it harm the performance?

不,只有更新才会跨线程传播。整个数据存储不会被重新读取,因此当您将保存分解为较小的 block 时,它实际上会提高性能,因为您将在主线程上以较小的 block 更新 UI,因此UI 看起来会表现得更好。

但是,在应用程序完成之前担心性能是应该避免的预优化。猜测什么会表现良好,什么不会表现通常是一个坏主意。

关于iPhone:带有委托(delegate)的 NSFetchedResultsController 和来自单独线程的数据更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3364769/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com