在后台线程中使用 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
Magical Record - 在主线程块 ui 中获取,在后台返回 nil