如何让 tableView.reloadData() 与核心数据正常工作?
Posted
技术标签:
【中文标题】如何让 tableView.reloadData() 与核心数据正常工作?【英文标题】:How do I get tableView.reloadData() to work properly with core data? 【发布时间】:2019-12-06 04:07:35 【问题描述】:当我运行应用程序时,我可以填充我的tableview
中的单元格,但是当我保存(从单独的视图控制器)并返回到tableview controller
时,tableView.reloadData() 被调用但没有任何反应。我使用通知中心重新加载数据,然后再弹出。
TableViewController.swift:
lazy var fetchedResultsController: NSFetchedResultsController<Pet> =
let fetchRequest = PersistenceManager.shared.fetchRequest()
let context = PersistenceManager.shared.context
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
return frc as! NSFetchedResultsController<Pet>
()
override func viewDidLoad()
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(pushToAddPetViewController))
tableView.register(MainTableViewCell.self, forCellReuseIdentifier: "cell")
do
try fetchedResultsController.performFetch()
tableView.reloadData()
catch let err
print(err)
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
@objc func loadList(notification: NSNotification)
DispatchQueue.main.async
self.tableView.reloadData()
AddPetVC.swift:
func saveContext()
// Inputs saved to coreData
PersistenceManager.shared.saveContext()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
self.navigationController?.popViewController(animated: true)
【问题讨论】:
【参考方案1】:您在 viewDidLoad() 中获取了数据,当您返回视图时不会调用该数据。您应该在 viewWillAppear() 中获取数据并从中重新加载或从通知观察者方法 loadList(notification: NSNotification) 重新加载。因此,在 viewWillAppear() 或 loadList(notification: NSNotification) 中添加以下代码:
do
try fetchedResultsController.performFetch()
tableView.reloadData()
catch let err
print(err)
【讨论】:
【参考方案2】:当你popViewController回调之前的ViewController时,不会调用viewWillAppear()。
【讨论】:
【参考方案3】:创建 fetchedResultsController 实例并符合 NSFetchedResultsControllerDelegate。 NSFetchedResultsControllerDelegate 会观察变化并将变化反映在 UI 上
lazy var fetchedResultsController: NSFetchedResultsController<Pet> =
let fetchRequest = PersistenceManager.shared.fetchRequest()
let context = PersistenceManager.shared.context
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc as! NSFetchedResultsController<Pet>
()
在你看来DidLoad
do
try fetchedResultsController.performFetch()
catch
let fetchError = error as NSError
print("Unable to Save Note")
print("\(fetchError), \(fetchError.localizedDescription)")
现在实现 NSFetchedResultsControllerDelegate
extension YourController: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
uiTableView.beginUpdates()
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
uiTableView.endUpdates()
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
switch (type)
case .insert:
if let indexPath = newIndexPath
uiTableView.insertRows(at: [indexPath], with: .fade)
break;
case .delete:
if let indexPath = indexPath
uiTableView.deleteRows(at: [indexPath], with: .fade)
break;
case .update:
if let indexPath = indexPath, let cell = uiTableView.cellForRow(at: indexPath) as? UserCell
configureCell(cell, at: indexPath)
break;
case .move:
if let indexPath = indexPath
uiTableView.deleteRows(at: [indexPath], with: .fade)
if let newIndexPath = newIndexPath
uiTableView.insertRows(at: [newIndexPath], with: .fade)
break;
实现 UITableViewDataSource & UITableViewDelegate
extension YourController: UITableViewDataSource, UITableViewDelegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
guard let sections = fetchedResultsController.sections else
return 0
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "PetCell", for: indexPath) as! Pet
configureCell(cell, at: indexPath)
return cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
let pet = fetchedResultsController.object(at: indexPath)
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
return true
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
if (editingStyle == .delete)
// handle delete (by removing the data from your array and updating the tableview)
//let user = viewModel.user(for: indexPath.row)
let pet = fetchedResultsController.object(at: indexPath)
//Delete pet and reload table
func configureCell(_ cell: Pet, at indexPath: IndexPath)
let pet = fetchedResultsController.object(at: indexPath)
更多细节和代码请关注演示项目 https://github.com/rheyansh/CoreDataDemo
【讨论】:
以上是关于如何让 tableView.reloadData() 与核心数据正常工作?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 UITableView contentOffset 在 tableview reloadData 期间变化很大,而不是保持不变? reloadData 后如何使其保持不变?
未调用 tableView reloadData cellForRowAtIndexPath
[self.tableview reloadData];导致闪烁
使用 tableView.reloadData() 重新加载 TableView 的问题