【问题标题】:NSFetchedResultsController not displaying changes from background threadNSFetchedResultsController 不显示来自后台线程的更改
【发布时间】:2011-07-03 19:28:40
【问题描述】:

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

问题是我的后台操作完成后,新的(或更新的)项目没有出现在我的 UITableView 中。根据我有限的理解,我认为我需要通知主 managedObjectContext 发生了更改,以便它们可以被合并。我的通知正在触发,但表格视图中没有出现新项目。如果我停止应用程序并重新启动它,对象会出现在 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]; 
}

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

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 = 

【问题讨论】:

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


    【解决方案1】:

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

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

    希望对您有所帮助。

    【讨论】:

    • 感谢您的回复。您在我的示例底部的 contextDidSave: 中建议的不是相同的事情吗?
    【解决方案2】:

    根据您所做工作的具体情况,您可能会以错误的方式处理此问题。

    在大多数情况下,您可以使用NSFetchedResultsControllerDelegate 简单地分配一个代表。您根据需要为“respondingToChanges”中指定的方法之一提供实现,然后向 tableView 发送 reloadData 消息。

    【讨论】:

    • 我正在使用 NSFetchedResultsControllerDelegate 进行其他操作,例如搜索 tableview,但我的印象是要异步更新 Core Data 存储,我需要创建一个单独的 managedObjectContext 然后合并由于 NSManagedObjectContext 不是线程安全的,因此发生了变化。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我在模拟器中遇到了类似的问题。从根表转换到所选文件夹时,我正在启动更新过程。更新过程将从 Web 服务器更新 CoreData,保存,然后合并,但数据没有显示出来。如果我来回浏览几次,它最终会出现,并且一次它就像发条一样工作(但我永远无法重复完美的运行)。这让我想到,这可能是模拟器中的线程/事件计时问题,表刷新太快或通知没有正确排队或类似的东西。我决定尝试在 Instruments 中运行,看看是否可以查明问题(所有 CoreData、CPU Monitor、Leaks、Allocations、Thread States、Dispatch 等等)。从那以后,每次我用一张白纸完成“第一次运行”时,它都能完美运行。也许 Instruments 的速度已经够慢了?

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-12
        • 1970-01-01
        • 2011-01-10
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多