NSFetchedResultsController不显示后台线程的更改

时间:2011-07-03 19:28:41

标签: objective-c ios cocoa-touch core-data

我的应用程序正在使用绑定到Core Data存储的NSFetchedResultsController,它到目前为止运行良好,但我现在正试图使更新代码异步,我遇到了问题。我创建了一个NSOperation子类来进行更新,并成功将这个新对象添加到NSOperationQueue中。更新代码正在按照我的预期执行,我已通过调试日志和运行后检查SQLite存储来验证这一点。

问题是我的后台操作完成后,新的(或更新的)项目不会出现在我的UITableView中。基于我有限的理解,我认为我需要通知主要的managedObjectContext发生了更改,以便它们可以合并。我的通知是触发,坚果没有新项目出现在tableview中。如果我停止应用程序并重新启动它,对象将出现在tableview中,这使我相信它们已成功插入到核心数据存储中,但未被合并到主线程上使用的managedObjectContext中。

我已经包含了我的操作的init,main和notification方法的示例。我错过了一些重要的事情,或者可能以错误的方式解决这个问题吗?任何帮助将不胜感激。

- (id)initWithDelegate:(AppDelegate *)theDelegate
{
    if (!(self = [super init])) return nil;
    delegate = theDelegate;
    return self;
}

- (void)main
{
    [self setUpdateContext:[self managedObjectContext]];
    NSManagedObjectContext *mainMOC = [self newContextToMainStore];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self 
               selector:@selector(contextDidSave:) 
                   name:NSManagedObjectContextDidSaveNotification 
                 object:updateContext];
    [self setMainContext:mainMOC];

    // Create/update objects with mainContext.

    NSError *error = nil;
    if (![[self mainContext] save:&error]) {
        DLog(@"Error saving event to CoreData store");
    }
    DLog(@"Core Data context saved");
}


- (void)contextDidSave:(NSNotification*)notification
{
    DLog(@"Notification fired.");
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
    [[delegate managedObjectContext] performSelectorOnMainThread:selector
                                                      withObject:notification
                                                   waitUntilDone:YES]; 
}

在调试时,我检查了notification中发送的contextDidSave:对象,它似乎包含了所有已添加的项目(摘录如下)。这继续让我认为插入/更新正确发生,但不知何故合并没有被解雇。

NSConcreteNotification 0x6b7b0b0 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0x5e8ab30>; userInfo = {
inserted = "{(\n    <GCTeam: 0x6b77290> (entity: GCTeam; id: 0xdc5ea10 <x-coredata://F4091BAE-4B47-4F3A-A008-B6A35D7AB196/GCTeam/p1> ; data: {\n    changed = 

4 个答案:

答案 0 :(得分:0)

接收通知的方法必须确实通知您的上下文,您可以尝试这样的事情,这就是我在我的应用程序中所做的事情:

 - (void)updateTable:(NSNotification *)saveNotification
  {
    if (fetchedResultsController == nil)
    {
       NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
    //Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }       
}
else
{
    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    // Merging changes causes the fetched results controller to update its results
    [context mergeChangesFromContextDidSaveNotification:saveNotification];
    // Reload your table view data  
    [self.tableView reloadData];
}
}

希望有所帮助。

答案 1 :(得分:0)

根据您所做的具体情况,您可能会采取错误的方式。

对于大多数情况,您只需使用NSFetchedResultsControllerDelegate分配代理即可。您根据需要为“respondToChanges”中指定的方法之一提供实现,然后向tableView发送reloadData消息。

答案 2 :(得分:0)

答案结果与发布的代码无关,最终按照我的预期运作。由于我仍然不完全确定的原因,它与应用程序的首次启动有关。当我在创建Core Data存储后尝试在启动时运行更新操作时,它按预期工作。我通过在应用程序中预加载一个版本的sqlite数据库来解决这个问题,这样它就不需要在首次启动时创建一个空商店。我希望我理解为什么这解决了这个问题,但我正计划这样做。我要离开这里,希望别人可能觉得它很有用,而且不会像我这样浪费那么多时间。

答案 3 :(得分:0)

我在模拟器中遇到了类似的问题。从根表转换到选定文件夹时,我正在开始更新过程。更新过程将从Web服务器更新CoreData,保存,然后合并,但数据未显示。如果我来回浏览几次它最终会出现,而曾经它像发条一样工作(但我从来没有能够重复完美的运行)。这给了我一个想法,也许这是模拟器中的线程/事件计时问题,其中表刷新太快或通知只是没有正确排队或沿着这些线排队。我决定尝试在Instruments中运行,看看我是否可以查明问题(所有CoreData,CPU Monitor,Leaks,Allocations,Thread States,Dispatch等等)。从那时起,我每次都做了一次空白的“第一次运行”,它完美地运作了。也许仪器正在放慢速度吗?

最终我需要在设备上进行测试以获得准确的测试,如果问题仍然存在,我将在接受的答案中尝试您的解决方案(创建一个基本的sql-lite数据库来加载)。