Ios 在后台同步的同时在UI交互上操作核心数据上下文的最佳实践

Ios 在后台同步的同时在UI交互上操作核心数据上下文的最佳实践,ios,swift,core-data,Ios,Swift,Core Data,我已经在许多文章和讨论中研究了如何使用NSManagedObjectContext,但仍然找不到适合我的项目的体系结构 在我的应用程序中,有三个数据源可能会被修改,在同时发生冲突时按优先级排序(例如,云的优先级最低): 用户界面 可悲的信息 来自云的HTTP响应 因为我还不是iOS开发专家,所以我尽量避免对每个源使用多个上下文。然而,经过数周的反复试验,我不情愿地开始思考是否真的需要采用多语境方法 一开始,我尝试在主上下文上使用context.perform{}来执行所有数据更改操作(add/u

我已经在许多文章和讨论中研究了如何使用
NSManagedObjectContext
,但仍然找不到适合我的项目的体系结构

在我的应用程序中,有三个数据源可能会被修改,在同时发生冲突时按优先级排序(例如,云的优先级最低):

  • 用户界面
  • 可悲的信息
  • 来自云的HTTP响应
  • 因为我还不是iOS开发专家,所以我尽量避免对每个源使用多个上下文。然而,经过数周的反复试验,我不情愿地开始思考是否真的需要采用多语境方法

    一开始,我尝试在主上下文上使用
    context.perform{}
    来执行所有数据更改操作(add/update/delete,除了fetch)。我将fetch保持为一个同步函数,因为我希望数据获取是即时的,以便能够响应UI。然而,在这种方法下,我偶尔会收到
    “集合在被枚举时发生了变异”
    异常(我认为这可能发生在批处理数据的
    forEach
    map
    函数中)。我还发现,当后台队列中有大量记录要更新时,这种方法仍然会阻塞UI

    因此,我创建了一个背景上下文,并使用父子模型来操作数据。基本上,主上下文(父上下文)只负责获取数据,而后台上下文(子上下文)通过
    backgroundContext.perform{}
    操作所有数据更改(add/update/delete)。这种方法解决了UI块问题,但是集合突变错误仍然偶尔发生,在这种结构下会出现另一个问题:例如,当我在ViewController a中添加数据记录并移动到View Controller B时,应用程序会崩溃,即使后台上下文尚未完成添加数据记录,也会立即获取相同的数据

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

    我的主上下文(父上下文)和背景上下文(子上下文)如下启动:

    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
    }()
    
    合并功能如下:

    @objc func contextDidSaveContext(notification: NSNotification) {
        let sender = notification.object as! NSManagedObjectContext
    
        if sender === self._context {
            NSLog("******** Saved main Context in this thread")
            self._backgroundContext.perform {
                self._backgroundContext.mergeChanges(fromContextDidSave: notification as Notification)
            }
        } else if sender === self._backgroundContext {
            NSLog("******** Saved background Context in this thread")
            self._context.perform {
                self._context.mergeChanges(fromContextDidSave: notification as Notification)
            }
        }
        else {
            NSLog("******** Saved Context in other thread")
            self._context.perform {
                self._context.mergeChanges(fromContextDidSave: notification as Notification)
            }
            self._backgroundContext.perform {
                self._backgroundContext.mergeChanges(fromContextDidSave: notification as Notification)
            }
        }
    }
    

    如果您能提供有关核心数据结构的任何建议,我们将不胜感激。

    您是否探讨过使用NSFetchedResultsController来获取数据? NSFetchedResultsController提供了一种线程安全的方法来观察由于CoreData中的创建、更新或删除操作而导致的数据更改。 使用NSFetchedResultsController的委托方法更新UI。 理想情况下,
    controllerDidChangeContent
    delegate会指示您更新UI