核心数据。将NSFetchedResultsController与.privateQueueConcurrencyType上下文一起使用。如何从主线程获取数据

时间:2019-05-31 12:18:02

标签: ios swift multithreading uitableview core-data

我有一个具有表格视图的应用程序。应用在启动时将100000+ json行导入CoreData。

我使用批处理(250项)和NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)来分批写入数据库,而不阻塞主线程。

这些导入的数据应显示在表格视图中,并且用户将能够在导入过程中平滑滚动表格视图。

以前,我曾尝试使用.mainQueueConcurrencyType作为NSFetchedResultsController的上下文,但是在合并其他私有上下文时,它会冻结滚动。(因为合并是在主线程上执行 )。

我创建了NSFetchedResultsController以便在表视图中显示数据,并使用concurrencyType = .privateQueueConcurrencyType.设置NSManagedObjectContext

所以NSFetchedResultsController称它为 func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)后台线程上,并在后台线程上更改属性fetchedObjects

BUT func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell用于从主线程进行表视图调用。

因此fetchedObjects可以随时更改(通过后台线程)而不依赖于主线程,因此它会产生崩溃

(例如,当fetchedObjects被删除并且现在包含0个元素,但是func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int可能具有先前的fetchedObjects.count值。)

问题: 如何同步后台CoreData上下文的线程并从TableView的主线程访问数据?

代码:

class QuakesViewController: UITableViewController {


 var tmpQuakes = [Quake]()

 var changesStarted: Bool = false {
        didSet {
            tmpQuakes = changesStarted ? dataProvider.fetchedResultsController.fetchedObjects ?? [] : []
        }
  }

 func getQuake(byIndexPath indexPath: IndexPath) -> Quake? {
    return changesStarted ? tmpQuakes[indexPath.row] : dataProvider.fetchedResultsController.fetchedObjects?[indexPath.row]
 }

 func getCount() -> Int {
     return changesStarted ? tmpQuakes.count : dataProvider.fetchedResultsController.fetchedObjects?.count ?? 0
 }
}

// MARK: - UITableViewDataSource

extension QuakesViewController {

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let cell = tableView.dequeueReusableCell(withIdentifier: "QuakeCell", for: indexPath) as? QuakeCell else {
        print("Error: tableView.dequeueReusableCell doesn'return a QuakeCell!")
        return QuakeCell()
    }
    guard let quake = getQuake(byIndexPath: indexPath) else { return cell }

    cell.configure(with: quake)
    return cell
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return getCount()
}
}

// MARK: - NSFetchedResultsControllerDelegate

extension QuakesViewController: NSFetchedResultsControllerDelegate {

    /**
 Reloads the table view when the fetched result controller's content changes.
 */
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    DispatchQueue.main.sync {
        self.changesStarted = false
        self.tableView.reloadData()
    }
}

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    DispatchQueue.main.sync {
        self.changesStarted = true
    }
}
}

我可以在没有其他变量(例如tmpQuakeschangesStarted)的情况下进行同步吗?

与以下问题相同:CoreData child contexts, NSFetchedResultsController and main thread

0 个答案:

没有答案