在后台和 tableView.reloadData() 中获取核心数据对象

Posted

技术标签:

【中文标题】在后台和 tableView.reloadData() 中获取核心数据对象【英文标题】:Fetching Core Data object in the background and tableView.reloadData() 【发布时间】:2016-12-29 14:24:58 【问题描述】:

我想在后台加载 Core Data 对象,当它完成后,应该重新加载一个 TableView。下面的代码给出了一个空的tableView:

class ViewController: UIViewController 
 var fetchRequest: NSFetchRequest<Venue>!
 var venue:[Venue] = []
 var coreDataStack: CoreDataStack!

 override func viewDidLoad() 
      super.viewDidLoad()
      fetchRequest = Venue.fetchRequest()
      coreDataStack.storeContainer.performBackgroundTask (context) in
           do 
                self.venue = try context.fetch(self.fetchRequesrt)
            catch 
           
           DispatchQueue.main.async 
                self.tableView.reloadData()
           
      

但是如果我们在 viewDidLoad() 中编写代码而不使用上面的块,一切正常并且 tableView 填充了数据:

venue = try! coreDataStack.managedContext.fetch(fetchRequesrt)
tableView.reloadData()

上面的代码有什么问题? 非常感谢您的建议!

编辑。这是正确的解决方案:

class ViewController: UIViewController 
 var fetchRequest: NSFetchRequest<Venue>!
 var venue:[Venue] = []
 var coreDataStack: CoreDataStack!

 override func viewDidLoad() 
   super.viewDidLoad()
   fetchRequest = Venue.fetchRequest()
   coreDataStack.storeContainer.performBackgroundTask (context) in
   do 
    let venue = try context.fetch(self.fetchRequesrt)
    venue.map $0.objectID.forEachself.venue.append(self.coreDataStack.managedContext.object(with: $0) as! Venue)
    DispatchQueue.main.async 
     self.tableView.reloadData()
    
    catch 
   ...
   
  
  

使用 NSAsynchronousFetchRequest 类的另一种解决方案。上面的示例如下所示:

class ViewController: UIViewController 
  var fetchRequesrt: NSFetchRequest<Venue>!
  var venue:[Venue] = []
  var asyncFetchRequest: NSAsynchronousFetchRequest<Venue>!
  var coreDataStack: CoreDataStack!
  fetchRequest = Venue.fetchRequest()
  override func viewDidLoad() 
    super.viewDidLoad()
   asyncFetchRequest = NSAsynchronousFetchRequest(fetchRequest:fetchRequest, completionBlock:  [unowned self] 
   (result: NSAsynchronousFetchResult) in
  guard let venue = result.finalResult else  return 
   self.venue = venue
   self.tableView.reloadData()
   )
   do 
     try coreDataStack.managedContext.execute(asyncFetchRequest)
      catch 
      ...
     
    
   

【问题讨论】:

【参考方案1】:

在与 Core Data 和 TableView 本身交互时,您应该使用 NSFetchedResultController。它比您自己获取数据更加稳定和优化。

我对您的代码感到非常困惑,我从未见过这样的解决方案。也许您应该使用闭包和完成调用 reloadData 来创建函数,或者像这样将整个块放入beginUpdates

    self.tableView.beginUpdates()
coreDataStack.storeContainer.performBackgroundTask (context) in
           do 
                self.venue = try context.fetch(self.fetchRequesrt)
            catch /*error goes here*/
      
self.tableView.endUpdates()

无论如何,我强烈建议使用NSFetchedResultsController,因为它更容易执行后台任务。

【讨论】:

以上是关于在后台和 tableView.reloadData() 中获取核心数据对象的主要内容,如果未能解决你的问题,请参考以下文章

[tableView reloadData] 和 runloop

使用通知中心和 tableview.reloaddata() 不刷新表视图

每次视图出现时 tableView.reloadData()

iOS TableView reloadData刷新列表cell乱跳tableview闪动的问题。

reloadData后无法单击tableView单元格中的按钮

使用 tableView.reloadData() 重新加载 TableView 的问题