菜鸟教程小白 发表于 2022-12-11 19:09:13

ios - 在后台同步的同时在 UI 交互上操作 Core Data Context 的最佳实践


                                            <p><p>我已经研究了很多关于如何使用 <code>NSManagedObjectContext</code> 的文章和讨论,但仍然无法为我的项目找到令人满意的架构。 </p>

<p>在我的应用程序中,可以从三个来源修改数据,当同时发生冲突时按优先级排序(例如,云的优先级最低):</p>

<ol>
<li>用户界面,</li>
<li>BLE 消息,</li>
<li>来自云端的 HTTP 响应</li>
</ol>

<p>由于我仍然不是 iOS 开发方面的专家,因此我尽量避免为每个源使用多个上下文。然而,经过数周的反复试验,我很不情愿,但开始考虑是否真的需要采用多上下文方法。</p>

<p>一开始,我尝试在主上下文上使用 <code>context.perform { }</code> 来做所有的数据更改操作(<strong>add/update/delete</strong>,除了<strong>获取</strong>)。我将 fetch 保持为同步功能,因为我希望数据获取是即时的,以便可以响应 UI。但是,在这种方法下,我偶尔会收到 <code>"Collection <__NSCFSet: 0x000000000> was mutated while being enumerated"</code> 异常(我想这可能发生在 <code>forEach</code> 或 <code> map</code> 函数用于批量数据处理)。我还发现,当后台队列中有大量记录要更新时,这种方法仍然会阻塞 UI。</p>

<p>因此,我创建了一个后台上下文并使用父子模型来操作数据。基本上主上下文(父)只负责获取数据,而后台上下文(子)通过 <code>backgroundContext.perform { }< 操作所有数据更改(<strong>添加/更新/删除</strong>)/</code>。这种方法解决了 UI 阻塞问题,但是偶尔会出现 collection mutated 错误,并且在这种结构下还会出现另一个问题:例如,当我在 ViewController A 中添加一条数据记录并移动到 View Controller B 时,应用程序会崩溃,这即使后台上下文尚未完成添加数据记录,也会立即获取相同的数据。</p>

<p>因此,我想就我的项目中使用 Core Data 提出一些建议。在我的父子数据上下文模型下我做错了什么吗?或者,我应该不可避免地选择一个没有父子的真正的多上下文模型吗?怎么做?</p>

<p>我的主要上下文(父)和背景上下文(子)是这样启动的:</p>

<pre><code>lazy var _context: NSManagedObjectContext = {
      return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    }()

lazy var _backgroundContext: NSManagedObjectContext = {
    let ctx = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType)
    ctx.parent = self._context
    return ctx
}()
</code></pre>

<p>合并函数如下:</p>

<pre><code>@objc func contextDidSaveContext(notification: NSNotification) {
    let sender = notification.object as! NSManagedObjectContext

    if sender === self._context {
      NSLog(&#34;******** Saved main Context in this thread&#34;)
      self._backgroundContext.perform {
            self._backgroundContext.mergeChanges(fromContextDidSave: notification as Notification)
      }
    } else if sender === self._backgroundContext {
      NSLog(&#34;******** Saved background Context in this thread&#34;)
      self._context.perform {
            self._context.mergeChanges(fromContextDidSave: notification as Notification)
      }
    }
    else {
      NSLog(&#34;******** Saved Context in other thread&#34;)
      self._context.perform {
            self._context.mergeChanges(fromContextDidSave: notification as Notification)
      }
      self._backgroundContext.perform {
            self._backgroundContext.mergeChanges(fromContextDidSave: notification as Notification)
      }
    }
}
</code></pre>

<p>任何关于核心数据结构的建议都将不胜感激。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>您是否探索过使用 NSFetchedResultsController 来获取数据?
NSFetchedResultsController 提供了一种线程安全的方式来观察由于 CoreData 中的创建、更新或删除操作而导致的数据变化。
使用 NSFetchedResultsController 的委托(delegate)方法来更新 UI。
理想情况下,<code>controllerDidChangeContent</code> 委托(delegate)会给你一个更新 UI 的指示。 <a href="https://developer.apple.com/documentation/coredata/nsfetchedresultscontrollerdelegate" rel="noreferrer noopener nofollow">Documentation for reference</a> </p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 在后台同步的同时在 UI 交互上操作 Core Data Context 的最佳实践,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/47027771/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/47027771/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 在后台同步的同时在 UI 交互上操作 Core Data Context 的最佳实践