如何让 tableView.reloadData() 正确处理核心数据?
How do I get tableView.reloadData() to work properly with core data?
当我 运行 应用程序时,我能够填充 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)
}
您在 viewDidLoad() 中获取了数据,当您返回视图时不会调用该数据。您应该在 viewWillAppear() 中获取数据并从该数据或从通知观察器方法 loadList(notification: NSNotification) 重新加载。因此,在 viewWillAppear() 或 loadList(notification: NSNotification) 中添加以下代码:
do {
try fetchedResultsController.performFetch()
tableView.reloadData()
} catch let err {
print(err)
}
当你popViewController回调到之前的ViewController时,viewWillAppear()不会被调用。
创建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
中的单元格,但是当我保存(从单独的视图控制器)并返回到 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)
}
您在 viewDidLoad() 中获取了数据,当您返回视图时不会调用该数据。您应该在 viewWillAppear() 中获取数据并从该数据或从通知观察器方法 loadList(notification: NSNotification) 重新加载。因此,在 viewWillAppear() 或 loadList(notification: NSNotification) 中添加以下代码:
do {
try fetchedResultsController.performFetch()
tableView.reloadData()
} catch let err {
print(err)
}
当你popViewController回调到之前的ViewController时,viewWillAppear()不会被调用。
创建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