具有并发性的魔法记录

时间:2015-05-27 20:20:25

标签: ios multithreading magicalrecord

我在使用Core Data和Magical Record工作了一段时间并且出错后,正处于开发iOS应用程序的过程中:

  

错误:NULL _cd_rawData但对象没有变成错误

我在这个项目之前并不知道Core Data,因为事实证明我非常天真地认为我可以使用Magical Record而不用担心并发性,因为我没有专注于管理上下文的任何想法/工作主线程和后台线程。

在大量关于核心数据管理对象上下文和魔法记录的阅读之后,我理解:

  • NSManagedObjects不是线程安全的。
  • NSManagedObjectId是线程安全的。
  • 我可以使用:魔法记录的Entity *localEntity = [entity MR_inContext:localContext]来处理后台线程上下文中的实体。
  • 我应该使用Magical Record的saveWithBlock:completion:saveWithBlockAndWait:方法来获取用于后台线程的托管上下文。

关于我的申请的一些信息:

  • 我正在使用最新版本的Magical Record 2.2。
  • 我有一个后端服务器,我的应用程序会进行很多讨论。
  • 他们的沟通类似于Whatsapp,因为它使用后台线程与服务器通信并在成功响应时更新托管对象。
  • 我正在使用DataModel对象包装模型,这些对象将托管对象保存在数组中,以便快速参考UI /后台使用。

现在 - 我的问题是:

  1. 我应该只从UI线程获取吗?我可以在DataModel对象中保存托管对象吗?
  2. 如何从后台线程创建新实体并在DataModel对象中使用新创建的实体?
  3. 我应该使用最好的设计方案吗?特别是在向服务器发送请求并获得响应时,我应该创建一个新的托管上下文并在整个线程的活动中使用它吗?
  4. 如果一切都清楚,请告诉我。如果没有,我会尝试增加清晰度。

    任何帮助或指导都将不胜感激。

    谢谢!

1 个答案:

答案 0 :(得分:7)

我没有使用MagicalRecord,但这些问题与CoreData有关,而与MagicalRecord有关,所以我会尝试回答它们:)。

1)从主(UI)线程

获取

设计应用模型的方法有很多,所以我在几年内使用CoreData学到了两件重要的事情:

  • 处理UI时,总是在主线程上获取对象。正如你所说的那样,NSManagedObjects 是线程安全的,所以你不能(好吧,可以,但不应该)从不同的线程访问他们的数据。当您需要显示长列表时,NSFetchedResultsController是您最好的朋友(例如,对于消息 - 但请注意请求的批量大小)。

  • 您应该设计存储和提取快速响应。使用索引,仅获取所需的属性,预取关系等。

  • 另一方面,
  • 如果需要从大量数据中获取,可以在不同的线程上使用上下文并仅传输NSManagedObjectID。让我们说你的用户有大量的消息,你想向他展示特定联系人的最新消息。您可以创建后台上下文(私有并发),获取这10个消息ID(NSManagedObjectIDResultType),将它们存储在数组中(或任何其他合适的格式),将它们返回到主线程并仅获取这些ID。请注意,如果fetch需要很长时间,因为谓词/ sortDescriptor,如果"问题"正在将故障转化为对象(例如,存储在可转换属性中的大UIImage :))

2)在后台创建实体

您可以在后台上下文中创建对象,在保存上下文后存储它的NSManagedObjectID (对象在保存之前只有临时ID)并将其发送回主线程,在那里你可以通过ID执行获取并在主上下文中获取对象。

3)使用背景上下文

我不知道它是否是最好的,但我对NSManagedObjectContext观察和通知合并非常满意。查看: mergeChangesFromContextDidSaveNotification:

因此,您创建背景上下文,添加主上下文作为更改的观察者(NSManagedObjectContextObjectsDidChangeNotification),后台上下文自动向您发送有关所有更改的通知(每次执行保存) - 插入/更新/删除的对象(不用担心,您可以通过调用mergeChangesFromContextDidSaveNotification:来合并它)。这有许多优点,例如:

  • 所有内容都会自动更新(您在&#34中提取的每个对象;观察上下文"更新/删除)
  • 每个合并都在内存中运行(没有提取,没有在主线程上持久化)
  • 如果你实现NSFetchedResultsController的委托方法,一切都会自动更新(不完全是所有内容 - 见下文)

另一方面:

好吧,我希望它能回答你的问题。如果一切顺利,请不要犹豫,问:)

关于子情境的附注

还要看看儿童情境。它们也很强大。基本上每个子上下文在保存时将其更改发送到父上下文(在" base" context(没有父上下文)的情况下,它将其发送给持久协调器)。

例如,当您创建编辑/添加控制器时,您可以从主上下文创建子上下文并执行其中的所有更改。当用户决定取消操作时,您只需销毁(删除引用)子上下文,不会存储任何更改。如果用户决定接受他/她所做的更改,请保存子上下文并销毁它。通过保存子上下文,所有更改都会传播到它的父存储(在此示例中为主上下文)。请务必同时保存父上下文(在某些时候)以保留这些更改(保存:方法不会执行冒泡)。结帐documentation of managing parent store

快乐的编码!