在后台线程中使用 MagicalRecord 和 NSXMLParser

Posted

技术标签:

【中文标题】在后台线程中使用 MagicalRecord 和 NSXMLParser【英文标题】:Using MagicalRecord and NSXMLParser in a background thread 【发布时间】:2013-08-31 01:54:42 【问题描述】:

我正在使用 NSXMLParser 来处理需要在我的核心数据模型中结束的大型复杂 XML 文件。为此,我遵循 Conway 和 Hillegass 在 ios 书中讨论的设计模式,每次到达新节点并动态创建新节点时,都会更改 NSXMLParser 的委托。为了创建实体,我在解析过程中为每个新节点使用 MagicalRecord 的 MR_createEntity 来设置我的数据模型。解析完成后我调用

[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait]; 

将新实体保存到我的核心数据存储中。

这一切都很好,直到我最近决定将解析移到后台线程中。而且我注意到 XML 数据并不总是被导入。所以在谷歌搜索之后,我发现MR_createEntity 不应该在后台线程上使用(链接:https://github.com/magicalpanda/MagicalRecord/issues/298)。

那该怎么办?我看到了两种可能的解决方案:

    在解析过程中,只需创建一个基于 Foundation 的所有节点结构,混合 NSDictionaries 和 NSArrays。这可以在后台线程上完成。完成后,我返回主线程并使用MR_importValuesForKeysWithObject 或类似的东西将我的数据保存到Core Data 中(如此处所述:http://www.cimgf.com/2012/05/29/importing-data-made-easy/)。但这适用于深度嵌套的字典和数组的组合吗?

    在解析过程中,我没有调用MR_CreateEntity,而是使用

    [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext)
    
        MyEntity *entity = [MyEntity MR_createInContext:localContext];
    ];
    

每次我遇到上面 github 链接中建议的新节点时。

那么在我开始切割和修改我的代码之前,应该怎么做?也许还有另一种方法?

【问题讨论】:

【参考方案1】:

如果我正确理解 MagicalRecord 源代码,您只需要 单个 saveInBackgroundWithBlock:completion:电话:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) 
      // ... parse XML ...
      // ... create entities with:
      MyEntity *entity = [MyEntity MR_createInContext:localContext];
      // ...
 completion:^
    NSLog("Import finished");
];

这个

创建一个临时背景上下文, 在与该上下文关联的后台队列中执行第一个块, 调用MR_saveToPersistentStoreAndWait 将临时上下文保存到 主上下文将主上下文保存到持久核心, 最后执行完成块。

【讨论】:

谢谢,我尝试了上面的方法,我可以看到所有正在执行的代码,但是在我的完成块中,我最终得到“成功 = NO,并且错误 = nil”(不推荐使用 saveInBackgroundWithBlock,并且替换 saveWithBlock 在完成块中有一个 BOOL 和 NSError )。所以数据没有保存到存储中。在创建每个实体时,我还使用 [NSManagedObjectContext MR_contextForCurrentThread] 来获取 localContext。也许这是错的? @Koen: saveWithBlock:completion 应该也可以,但是“成功=否,错误=无”很奇怪,我不知道为什么会发生这种情况。但是,我会避免使用MR_contextForCurrentThread(比较***.com/questions/17814656/… 的讨论)。您应该使用传递给块的localContext 我现在通过给所有实体一个上下文属性来传递本地上下文和解析器,现在它可以工作了。仍然不确定这是否是最有效的方法(与我最初的问题中的提案 1. 相反)。我会在今天晚些时候或周末之后再看一遍。【参考方案2】:

你试试这个? https://***.com/a/13924299/1979953

像这样。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
  // dispatch_async mean your NSXMLParser in a backgound thread
  MyEntity *entity = [MyEntity MR_createEntity];

  ...

  [[NSManagedObjectContext MR_contextForCurrentThread] saveNestedContexts];
);

但是,您发现不应在后台线程上使用 MR_createEntity。所以我很困惑。

【讨论】:

以上是关于在后台线程中使用 MagicalRecord 和 NSXMLParser的主要内容,如果未能解决你的问题,请参考以下文章

如何确保在使用 MagicalRecord 3.0 保存后台线程后通知 NSFetchedResultsController

正确设置 MagicalRecord 以在后台线程上保存 rootSavingContext

在 CoreData 的后台线程中创建实体

Magical Record - 在主线程块 ui 中获取,在后台返回 nil

更改无法识别我的 NSFetchedResultsController 附加到后台线程

MagicalRecord 插入太慢