【问题标题】:Core Data multi-threading核心数据多线程
【发布时间】:2011-02-07 21:23:47
【问题描述】:

我的应用程序首先呈现一个表视图,其数据源是 Core Data SQLite 存储。当应用程序启动时,会创建一个具有自己的商店控制器和上下文的辅助线程,以从 Web 获取商店中数据的更新。但是,对存储的任何结果更改都不会通知给 fetchedresults 控制器(我推测是因为它有自己的协调器),因此表不会随着存储更改而更新。在主线程上刷新上下文的最有效方法是什么?我正在考虑跟踪在辅助线程上更改的任何对象的 objectID,在辅助线程完成时将它们发送到主线程并调用“[context refreshObject:....] 任何帮助将不胜感激。

【问题讨论】:

    标签: iphone cocoa cocoa-touch core-data


    【解决方案1】:

    在您的NSFetchedResultsController 处理表格中,注册viewDidLoadloadView 以获取通知:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:@"ContextDidSave" object:nil];
    

    当辅助线程准备好新数据时,只需像往常一样保存上下文,然后发布通知:

    [[NSNotificationCenter defaultCenter] postNotificationName:@"ContextDidSave" object:managedObjectContext];
    

    通知将在您的NSFetchedResultsController 中使用以下方法处理:

    编辑:在与 bbum 深入讨论后,修改了以下方法,正确考虑了多线程。

    - (void)contextDidSave:(NSNotification *)notification
    {
    
        SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
        [[[[UIApplication sharedApplication] delegate] managedObjectContext] performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES];
    
    }
    

    对于 UI 更新,可以使用 NSFetchedResultsController 委托方法自动完成。

    最后,记得在NSFetchedResultsControllerdealloc方法中添加以下内容:

    [[NSNotificationCenter defaultCenter] removeObserver:self];
    

    【讨论】:

    • dealloc() 和 loadView() 怎么办?这不是表示 Objective-C 方法的标准方式。使用-dealloc-loadView 来减少混淆。
    • 等等。这个答案不正确;它会导致数据的重新加载发生在错误的线程中。
    • 我已经按照建议使用了 performSelectorOnMainThread:withObject:waitUntilDone:,因为这解决了通知传递问题。但是我的跨线程合并存储更改的主要问题得到了解答。因为我已经实现了 fetchedresultscontroller 委托,所以我也不需要显式地重新加载表。
    【解决方案2】:

    Unforgiven 的回答没有正确处理线程。特别是,文档状态(强调我的):

    如果您的应用程序具有图形 用户界面,建议 您收到与用户相关的事件和 从您的启动界面更新 应用程序的主线程。这 方法有助于避免同步 与处理用户相关的问题 事件和绘图窗口内容。 一些框架,例如 Cocoa, 通常需要这种行为,但是 即使对于那些不这样做的人,保持 主线程上的这种行为有 简化逻辑的优点 用于管理您的用户界面。

    通知观察者将在通知最初发布的任何线程上被触发。因此,您不能直接从后台线程发布的通知中调用 NSTableView 的reloadData

    根本不需要使用通知。在您的后台线程中,当准备好更新用户界面时,使用多种机制中的任何一种来重新加载主线程中的数据——在管理主事件循环和用户界面的线程中。

    [tableView performSelectorOnMainThread: @selector(reloadData)
               withObject: nil waitUntilDone: YES];
    

    您也可以使用 Grand Central Dispatch 或 NSOperation 来做类似的事情。

    【讨论】:

    • 这里的主要问题不是更新 UI(它甚至可以由 NSFetchedResultsController 委托方法自动完成),而是合并在后台线程中检索到的更新对象。答案基于 Core Data 如何处理不同线程中 NSManagedObjects 的插入、删除或编辑。另一种可能性是做 SEL 选择器 =@selector(mergeChangesFromContextDidSaveNotification:); [[[[UIApplication sharedApplication] delegate] managedObjectContext] performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES];在通知方法中。
    • 是的——我的回答并没有真正解决 OP 的问题,而是更多的线程问题。实际上,您的建议是一个更好的答案。修复上面的答案以处理线程问题并提出这些建议,我很乐意删除我的劣质答案。
    猜你喜欢
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多