具有并发性的魔法记录

Che*_*ery 1 multithreading ios magicalrecord

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

错误:NULL _cd_rawData但该对象未被转换为错误

我在这个项目之前并不知道Core Data,因为事实证明我很天真地认为我可以使用Magical Record而不用担心并发性,因为我没有专门针对主线程的任何关于托管上下文的想法/工作和背景线程.

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

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

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

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

现在 - 我的问题是:

  1. 我应该只从UI线程获取?我可以在DataModel对象中保存托管对象吗?
  2. 如何从后台线程创建新实体并在DataModel对象中使用新创建的实体?
  3. 我应该使用最好的设计方案吗?特别是在向服务器发送请求并获得响应时,我应该创建一个新的托管上下文并在整个线程的活动中使用它吗?

如果一切都清楚,请告诉我.如果没有,我会尝试增加清晰度.

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

谢谢!

Jak*_*lik 7

我不使用MagicalRecord,但这些问题与CoreData相关而不是与MagicalRecord相关,所以我会尝试回答它们:).

1)从主(UI)线程获取

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

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

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

  • 另一方面,如果需要从大量数据中获取,则可以在不同的线程上使用上下文并仅传输NSManagedObjectID.假设您的用户有大量的消息,并且您希望向他显示特定联系人的最新消息.您可以创建后台上下文(私有并发),获取这10个消息ID(NSManagedObjectIDResultType),将它们存储在数组中(或任何其他合适的格式),将它们返回到主线程并仅获取这些ID.请注意,如果fetch需要很长时间,因为谓词/ sortDescriptor,如果"问题"在将错误转换为对象的过程中(例如,存储在可转换属性中的大UIImage :),这种方法会加快速度.)

2)在后台创建实体

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

3)使用背景上下文

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

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

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

另一方面:

  • 注意合并策略(NSMangedObjectContext mergePolicy)
  • 用于引用从后台删除的托管对象的注意事项(或仅仅是另一个上下文)
  • NSFetchedResultsController仅更新"直接"属性的更改(结帐此SO问题)

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

关于儿童情境的旁注

还要看看孩子的背景.它们也很强大.基本上每个子上下文在保存时将其更改发送到父上下文(在"基本"上下文(没有父上下文)的情况下,它将其更改发送到持久协调器).

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

快乐的编码!