iPhone:NSFetchedResultsController与委托和数据更新从一个单独的线程 [英] iPhone: NSFetchedResultsController with delegate and data update from a separate thread

查看:270
本文介绍了iPhone:NSFetchedResultsController与委托和数据更新从一个单独的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,对于太长的问题,抱歉。

First of all, sorry for the too long question.

我知道这里有几个问题讨论类似的问题,但没有一个谈到NSFetchedResultsController委托与单独线程中的更新一起。

这些是现有的问题:

I know that there are few questions here that discuss similar issues but none of these talks about NSFetchedResultsController with delegate together with update in separate thread. And none of the solutions has helped me.
These are the existing questions:

  • NSFetchedResultsController: using of NSManagedObjectContext during update brings to crash
  • Determining which core Data attribute/property change triggered a NSFetchedResultsController update
  • Core Data executeFetchRequest throws NSGenericException (Collection was mutated while being enumerated)
  • Collection was mutated while being enumerated. How to determine which set?
  • etc.


  • 我有一个单独的线程从网络更新核心数据对象(使用套接字)。

  • 很少有视图控制器显示来自同一个核心数据对象的数据(每个选项卡包含一个显示其过滤数据的视图控制器)。

  • 每个视图控制器都有自己的 NSFetchedResultsController 的实例,并将委托设置为self。

  • I have a separate thread that updates the core data objects from the web (using a socket).
  • There are few view controllers that display the data from the same core data object (each tab contains a view controller that displays its filtered data).
  • Each view controller has its own instance of NSFetchedResultsController and the delegate is set to self.

在枚举时被突变在更新单独线程中的数据时发生异常,有时会导致应用程序崩溃。

Sometimes I receive was mutated while being enumerated exception on updating the data in the separate thread and sometimes it crashes the app.

已经做了许多代码操作,以试图解决它,似乎没有什么帮助。

我试图不直接使用托管对象从表视图数据源方法。而不是我创建了一个数组,其中包含字典列表。我从上面的 didChangeObject 方法中填充这些字典。这样我不会在视图控制器中触摸被管理对象。

I have done many code manipulations in order to try to fix it and seems that nothing helps.
I have tried not to use the managed object directly from table view datasource methods. Instead of that I have created an array which holds a list of dictionaries. i fill those dictionaries in the didChangeObject method from above. This way I don't touch the managed objects at all in the view controller.

然后我已经理解,问题是在NSFetchedResultsController,可能,迭代数据每时每刻。这是在单独的线程中与我的数据更新冲突的对象。

And then I have understood that the problem is in NSFetchedResultsController that, probably, iterates the data all the time. And this is the object that conflicts with my data update in the separate thread.

问题是如何在独立线程中更新核心数据对象NSFetchedResultsController with delegate(意味着它监视数据并一直更新delagate)。

The question is how can I update the core data objects in the separate thread once I have a NSFetchedResultsController with delegate (meaning that it "watches" the data and updates the delagate all the time).

NSFetchedResultsControllerDelegate实现:

NSFetchedResultsControllerDelegate implementation:

- (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];
}



在表视图数据源方法中,我直接使用托管对象。 p>

In the table view datasource methods I work directly with the managed object.

推荐答案

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

Two separate questions here. First, if you are getting mutating errors that means you are mutating a set or array (or relationship) while iterating over that set/array/relationship. Find where you are doing that and stop doing it. That is the only solution.

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

As for your updates. Your background NSManagedObjectContext should be saving periodically. Your main thread should be listening for NSManagedObjectContextDidSaveNotification and when it receives one it calls the main NSManagedObjectContext on the main thread (as the notification will most likely come in on the background thread) via -mergeChangesFromContextDidSaveNotification: which takes the NSNotification as a parameter. This will cause all of your NSFetchedResultController instances to fire their delegate methods.

很简单。


ank你的回复。在后台线程中更新NSManagedObjectContext时抛出异常。我在两个线程中使用相同的NSManagedObjectContext。应用程序应尽可能接近实时应用程序 - 更新不断,表应该立即更新。我不保存 - 我只更新NSManagedObjectContext。我看到在提到的问题之一,有人用来分离NSManagedObjectContext的实例,但他仍然收到相同的异常,一旦他合并的更改。那么,你建议使用2个单独的NSManagedObjectContext?

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中的多线程:)。

First, read up on multi-threading in Core Data from Apple's documentation (or my book :).

其次,你应该每个线程有一个上下文,这是Core Data和多线程的黄金规则之一(另一个是不要通过 NSManagedObject 跨线程实例)。这可能是您的崩溃的根源,如果不是它将是未来崩溃的根源。

Second, yes you should have one context per thread, that is one of the golden rules of Core Data and multi-threading (the other is don't pass NSManagedObject instances across threads). That is probably the source of your crash and if it isn't it is going to be the source of a crash in the future.


我有大量的数据,我只更新表中修改/新/删除的项目。如果我将开始保存,那么它会损害性能吗?

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?

不,只有更新将通过线程传播。整个数据存储将不会被重新读取,因此,当你将保存分解成更小的块时,它实际上会提高性能,因为你将在主线程上,更新UI,以较小的块,所以UI会表现更好。

No, only the updates will be propagated across the threads. The entire data store will not be re-read so it will actually improve performance when you break up the saves into smaller chunks because you will be on the main thread, updating the UI, in smaller chunks so the UI will appear to perform better.

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

However, worrying about performance before the app is completed is a pre-optimization that should be avoided. Guessing at what is going to perform well and what won't is generally a bad idea.

这篇关于iPhone:NSFetchedResultsController与委托和数据更新从一个单独的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆