在使用Core Data和Magical Record并花费了一段时间后出现错误,我正在开发iOS应用程序:



我在这个项目之前并不了解Core Data,事实证明我很天真地认为我可以与Magical Record一起工作而不必担心并发性,因为我没有针对主线程对托管上下文进行任何思考/工作。和背景线程。

在阅读了大量有关核心数据管理对象上下文和魔术记录的内容之后,我了解到:

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

  • 有关我的应用程序的一些信息:
  • 我使用的是Magical Record的最新版本,为2.2。
  • 我有一个后端服务器,我的应用程序经常与之通信。
  • 它们的通信类似于Whatsapp,因为它使用后台线程与服务器通信并在成功响应后更新托管对象。
  • 我将模型与DataModel对象包装在一起,这些对象将受管对象保存在数组中,以便快速引用UI/后台使用。

  • 现在-我的问题是:
  • 我应该仅从UI线程获取吗?我可以将托管对象保存在DataModel对象中吗?
  • 如何从后台线程创建新实体并在DataModel对象中使用新创建的实体?
  • 我应该使用最佳设计方案吗?特别是在向服务器发送请求并获得响应时,是否应该创建一个新的托管上下文并在整个线程 Activity 中使用它?

  • 让我知道一切是否清楚。如果没有,我将尝试增加清晰度。

    任何帮助或指导方针,将不胜感激。

    谢谢!

    最佳答案

    我没有使用MagicalRecord,但是这些问题与CoreData而不是与MagicalRecord有关,因此,我将尝试回答它们:)。

    1)从主(UI)线程获取

    设计应用程序模型的方法有很多,因此我几年来使用CoreData学会了两个重要的知识:

  • 在处理UI时,总是在主线程上获取对象。正如您正确指出的那样,NSManagedObjects是而不是线程安全的,因此您不能(很好,可以但不应)从其他线程访问它们的数据。 NSFetchedResultsController是您最好的 friend ,当您需要显示较长的列表时(例如,用于显示消息,但要注意请求的batchSize)。
  • ,您应该设计存储和获取方式,以便快速响应。使用索引,仅获取所需的属性,预取关系等。
  • 另一方面,如果需要从大量数据中获取
  • ,则可以在其他线程上使用上下文,并且仅传输NSManagedObjectID。假设您的用户有大量消息,并且您想向他显示来自特定联系人的最新消息。您可以创建后台上下文(私有(private)并发),获取这10个消息ID(NSManagedObjectIDResultType),将它们存储在数组中(或任何适合您的其他格式),将它们返回到主线程,并仅获取这些ID。请注意,如果由于谓词/sortDescriptor而导致获取时间较长,则此方法将加快处理速度,而不是如果“问题”正处于将错误变为对象的过程中(例如,存储在transformable属性中的大UIImage :))

  • 2)在后台创建实体

    您可以在后台上下文中创建对象,保存上下文后将其存储为NSManagedObjectID (对象在保存之前只有临时ID),然后将其发送回主线程,在其中您可以按ID进行获取并在主线程中获取对象语境。

    3)使用背景上下文

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

    因此,您创建背景上下文,将主要上下文添加为更改的观察者(NSManagedObjectContextObjectsDidChangeNotification),并且背景上下文会自动向您发送有关所有更改的通知(每次执行保存)–插入/更新/删除的对象(不用担心,您可以通过调用mergeChangesFromContextDidSaveNotification:合并它)。这具有许多优点,例如:
  • 一切都会自动更新(您在“观察上下文”中获取的每个对象都会被更新/删除)
  • 每次合并都在内存中运行(不提取,也不在主线程上持久保存)
  • 如果您实现NSFetchedResultsController的委托(delegate)方法,则所有内容都会自动更新(不完全是所有内容–参见下文)

  • 另一方面:
  • 注意合并策略(NSMangedObjectContext mergePolicy)
  • 监视,以引用已从后台(或只是另一个上下文)删除的托管对象
  • NSFetchedResultsController仅在更改“直接”属性( check out this SO question)时才更新

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

    有关子上下文的旁注

    也请看一下 child 的情况。他们也可以强大。基本上,每个子上下文在保存时都会将其更改发送到父上下文(如果是“基础”上下文(没有父上下文),则将其更改发送到持久协调器)。

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

    祝您编码愉快!

    10-07 22:53