【问题标题】:Swift delete core data on background thread not updating MOCSwift删除后台线程上的核心数据不更新MOC
【发布时间】:2020-12-12 06:37:31
【问题描述】:

我试图了解后台线程并通过后台 MOC 操作 CoreData,但在从 CoreData 删除大量记录时遇到了一些障碍

我的设置是,我有许多(主要)记录,每个记录可以通过一对多关系关联到 0 到几千个(次要)记录

这由主/细节样式设置中的 2 个视图控制器表示。

ViewController A 有一个表格视图,列出了所有的主要记录。 然后,当点击 viewController A 上的单元格时,ViewController B 会显示相关记录

两个表都在主线程上填充,并使用 persistentContainer.viewContext 获取数据。

ViewController B 为用户提供了批量删除所有关联记录的选项,因此我希望在后台线程上完成此操作,以免阻塞主线程。

我遇到的问题是,如果我在处理完成之前删除记录并关闭 viewController B,它不会删除记录。 但是,如果我让 viewController B 打开直到删除完成,它会很好地删除它们。

我注意到的一件事是,如果我在删除线程完成之前关闭 ViewController B,则视图在后台删除过程结束之前不会取消初始化,因此在视图关闭后它似乎仍在删除,但是它似乎不会保存到持久存储中,除非我在进程完成之前让视图保持打开状态

这是我用来删除后台记录的代码:

class GlobalChanges....
      
static func deleteRecords(records: [NSManagedObject], managedContext: NSManagedObjectContext, finished: () -> Void){
        
    //create a new background MOC
    let coreDataManager = CoreDataStack.shared
    let backgroundContext = coreDataManager.persistentContainer.newBackgroundContext()
    backgroundContext.automaticallyMergesChangesFromParent = true
    
    backgroundContext.performAndWait {
        
        
        //remove the records from the managed context
        for record in records{
            
            let backgroundContextRecord = backgroundContext.object(with: record.objectID) as NSManagedObject
            
            //delete the record
            backgroundContext.delete(backgroundContextRecord)
            
        }
        
        
        do {
            //update core data
            try backgroundContext.save()
            
            managedContext.refreshAllObjects()

            finished()
                      
        } catch let error as NSError  {
            print("Could not save \(error), \(error.userInfo)")
        }
    }
}

当用户点击删除时调用:

   @IBAction func deleteButton(_ sender: UIButton) {
            
        let deleteQueue = DispatchQueue(label: "deleteQueue")
              
        deleteQueue.async {
            GlobalChanges.deleteRecords(records: self.selectedRows, managedContext: self.managedContext){
                
                DispatchQueue.main.async{
                    //update UI...
                }
            }
        }
    }

在删除过程完成之前关闭 ViewController B 时如何使数据保持不变?

提前致谢

【问题讨论】:

    标签: ios swift multithreading core-data


    【解决方案1】:

    我想对您的问题做出贡献的并不是您的问题本身的解决方案。但我想帮助您改进“批量删除所有关联记录”的方法。

    如果您确实想一次删除主要(主要)记录的所有辅助记录,CoreData 中的最佳方法是使用 .xcmod​​eld 文件的关系检查器编辑多对多关系并设置删除规则级联。

    然后您删除主记录本身。 Core Data 会自动将您的删除级联到所有辅助记录。无需您执行任何其他操作,它们也会被删除。

    如果您需要保留主要记录并仅清除关系,您可以考虑与将保存多对辅助记录的中间实体建立一对一关系。这样,您可以删除该中间实体,并将新实体分配给一对一关系。

    【讨论】:

    • 嗨,谢尔盖,感谢您的回复。我已经有级联删除规则集,如果用户删除主记录,它可以正常工作。不幸的是,中间记录不起作用,因为用户可以选择不删除,部分或全部记录,所以如果他们只删除一半,我将无法删除中间记录而不必重建所有再次对剩下的一半数据进行分析
    • 嗨,杰米,我明白了。我没有意识到并非所有二级记录都必须删除。顺便提一句。我看到你发布了一个答案。如果您不介意,可以与我们分享您的解决方案吗?
    • 嗨,Serge,我已经用我使用的解决方案更新了我的答案@SergePatriceLonla
    【解决方案2】:

    好的,我猜到了

    每次视图控制器 B 关闭时,它都会从剩余的(辅助)记录中计算总数,并将数据写回 ViewContext 上的(主)记录。

    由于 backgroundContext 和 ViewContext 都试图同时更新持久存储,这导致了合并冲突。

    更新: 为了解决这个问题,我将所有上下文写入排队,以便在任何给定时间对存储执行一次写入

    let persistentContainerQueue = OperationQueue()
    persistentContainerQueue.maxConcurrentOperationCount = 1
             
        func SaveBackgroundContext(backgroundContext: NSManagedObjectContext) {
            
            //add the save operation to the back of the queue
            persistentContainerQueue.addOperation(){
            
                backgroundContext.performAndWait{
                    
                    do {
                        //update core data
                        try backgroundContext.save()
                        
                        
                    } catch let error as NSError  {
                        print("Could not save \(error), \(error.userInfo)")
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      • 1970-01-01
      • 2012-12-12
      • 2020-01-09
      • 2019-06-19
      • 1970-01-01
      相关资源
      最近更新 更多