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

Posted

技术标签:

【中文标题】使用 tableView.reloadData() 重新加载 TableView 的问题【英文标题】:Problems to reload TableView with tableView.reloadData() 【发布时间】:2021-05-20 04:49:50 【问题描述】:

我对使用 swift 进行编程比较陌生,并且有一个问题一直困扰着我。

我有一个 TableView 控制器,您可以在其中输入电影的名称。 如果按下“完成”按钮,新输入的名称应出现在 TableView 中并与 CoreData 一起保存。 保存也很好用,但问题是新创建的名称只有在应用重启时才会出现在列表中。

现在我认为视图会用“tableView.reloadData()”重新加载。 不幸的是,他不会。

这就是我创建它的方式:

我的视图控制器:

import UIKit

class ViewController: UITableViewController 
    
    static let filmCellIndentifier = "filmCell"
    
    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)
        
        self.tableView.reloadData() // TODO: -> don´t reload Cell Data if "DoneButton" in "CreateFilmTableViewController" isn't pressed ???
    
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        title = "Filmbook"
    
    
    private func film(atIndexPath indexPath: IndexPath) -> Film 
        return CoreDataManager.shared.availableFilms()[indexPath.row]
    



extension ViewController 
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return CoreDataManager.shared.numberOfFilms
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let filmCell = tableView.dequeueReusableCell(withIdentifier: ViewController.filmCellIndentifier, for: indexPath)
        let film = self.film(atIndexPath: indexPath)
        filmCell.textLabel?.text = film.title
        return filmCell
        

我在这里创作一部新电影:

import UIKit
import CoreData

class CreateFilmTableViewController: UITableViewController 

    @IBOutlet weak var datePicker: UIDatePicker!
    @IBOutlet weak var titleTextField: UITextField!
  
    @IBAction func dismissButton(_ sender: UIBarButtonItem) 
        dismiss(animated: true, completion: nil)
    
     
    @IBAction func createFilmButton(_ sender: Any) 
        let title = titleTextField.text != nil ? titleTextField.text! : ""
        let date = datePicker.date
        CoreDataManager.shared.createFilmbook(withTitle: title, date: date)
        dismiss(animated: true, completion: nil)
        

还有我的 CoreData 管理器:

import Foundation
import CoreData

class CoreDataManager 

    static let shared = CoreDataManager()
    

    var numberOfFilms: Int 
        return availableFilms().count
    
 
    lazy var persistentContainer: NSPersistentContainer = 
        let container = NSPersistentContainer(name: "FilmbookT")
        container.loadPersistentStores(completionHandler:   (storeDescription, error) in
            if let error = error as NSError? 
 
                fatalError("Unresolved error \(error), \(error.userInfo)")
            
        )
        return container
    ()
    
    func createFilmbook(withTitle title: String, date: Date) 
        let film = Film(context: persistentContainer.viewContext)
        film.title = title
        film.date = date
        try! persistentContainer.viewContext.save() // TODO -> Error Handling -> ("try!")
        
    

    func availableFilms() -> [Film] 
        
        let filmFetchRequest = NSFetchRequest<Film>(entityName: "Film")
        filmFetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
        
        let availableFilms = try! persistentContainer.viewContext.fetch(filmFetchRequest) // TODO -> //Error Handling -> ("try!")
        
        return availableFilms
    

你能帮我找出错误吗? 非常感谢! :)

【问题讨论】:

按下done 按钮时,您是否尝试过reloadData 是的,我试过了,但是没有效果... 【参考方案1】:

您应该在视图控制器中有一个表视图数据源的局部变量,因此您不应该在 CoreDataManager 中有 availableFilms()numberOfFilms。经理的职责应该只是保存新添加的对象并返回目前添加的对象。

我现在回答了一个类似的问题,请查看这个答案:https://***.com/a/67616364/14675707

【讨论】:

【参考方案2】:

你有试过听CoreData的变化吗?创建新 Film 后,新对象可能尚未插入到 Core Data 中,因此 reloadData 无法获取新对象

NotificationCenter.default.addObserver(self, selector: #selector(contextObjectsDidChange(_:)), name: Notification.Name.NSManagedObjectContextObjectsDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contextWillSave(_:)), name: Notification.Name.NSManagedObjectContextWillSave, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contextDidSave(_:)), name: Notification.Name.NSManagedObjectContextDidSave, object: nil)

参考:https://medium.com/@marcosantadev/core-data-notifications-with-swift-acc8232a674e

但是,我同意@marci0907 的解决方案

【讨论】:

以上是关于使用 tableView.reloadData() 重新加载 TableView 的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何让 tableView.reloadData() 与核心数据正常工作?

[tableView reloadData] 和 runloop

tableview.reloaddata() 在使用 coredata 时搜索栏取消按钮后不起作用

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

在主线程上调用 tableView.reloadData 后 UITableView 不刷新

tableView reloadData 和 deselectRowAtIndexPath