如何让 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