每次显示视图控制器时CoreData数据重复添加至Table View问题
问题根因
- 你声明的
noteList是全局变量,生命周期和App进程一致,不会随NoteTableView页面销毁而清空。 firstLoad是NoteTableView的实例属性,每次重新打开页面生成新的控制器实例时,firstLoad都会重置为true,会再次触发CoreData查询,把查询到的所有笔记追加到已经有数据的全局noteList中,最终导致列表重复展示。
修复方案
- 把全局的
noteList移动到NoteTableView类内部作为私有实例属性,脱离全局生命周期,每次打开页面都会生成新的空数组。 - 直接将CoreData查询结果赋值给
noteList,避免循环append可能带来的冗余,也可以在查询前先清空数组进一步避免重复。 - 可选优化:取消
firstLoad判断,每次页面出现时都重新拉取CoreData数据,保证列表展示的是最新内容(比如你在编辑页新增/删除笔记后返回列表能自动刷新)。
修改后的完整代码如下:
import UIKit import CoreData class NoteTableView: UITableViewController { // 移动到类内部作为实例属性,每次新建页面实例都会生成新的空数组 private var noteList = [Note]() func nonDeletedNotes() -> [Note] { return noteList.filter { $0.deletedDate == nil } } override func viewDidLoad() { super.viewDidLoad() loadNotesFromCoreData() } // 封装CoreData查询逻辑 private func loadNotesFromCoreData() { let appDelegate = UIApplication.shared.delegate as! AppDelegate let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note") do { // 直接将查询结果赋值给noteList,不需要循环append if let results = try context.fetch(request) as? [Note] { noteList = results } } catch { print("Fetch Failed: \(error.localizedDescription)") } } // 新增/删除笔记后返回列表自动刷新 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) loadNotesFromCoreData() tableView.reloadData() } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let noteCell = tableView.dequeueReusableCell(withIdentifier: "noteCellID", for: indexPath) as! NoteCell let thisNote = nonDeletedNotes()[indexPath.row] noteCell.titleLabel.text = thisNote.title noteCell.descLabel.text = thisNote.desc1 return noteCell } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return nonDeletedNotes().count } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { self.performSegue(withIdentifier: "editNote", sender: self) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if(segue.identifier == "editNote") { let indexPath = tableView.indexPathForSelectedRow! let noteDetail = segue.destination as? FocusWheelViewController let selectedNote = nonDeletedNotes()[indexPath.row] noteDetail!.selectedNote = selectedNote tableView.deselectRow(at: indexPath, animated: true) } } }
内容的提问来源于stack exchange,提问作者Rem Biths Wind
相关产品推荐
相关产品推荐

