Ken*_*uch 4 core-data uitableview ios swift
我没有找到我遇到的问题的答案。我正在使用 NSFetchedResultsControllerDelegete 将我的表视图与我的数据连接起来。我正在使用 sectionNameKeyPath 设置检索数据,以便我可以在表视图中对项目进行分组。如果我在表视图的一部分中只有一个项目并将其删除,则会出现以下错误:
无效更新:节数无效。更新后表视图中包含的节数(1)必须等于更新前表视图中包含的节数(2),加上或减去插入或删除的节数(0插入,0删除)。
这是我删除前的屏幕:
这是我的视图代码:
import CoreData
class VehicleTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var deleteItemIndexPath: IndexPath? = nil
lazy var dao: DAOUtilities = {
return DAOUtilities(context: GlobalVariables.getContext())
}()
lazy var fetchedResultsController: NSFetchedResultsController<Vehicles> = {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Vehicles")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "activeFlag", ascending: false), NSSortDescriptor(key: "vehicleDesc", ascending: true)]
// Initialize Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: GlobalVariables.getContext(), sectionNameKeyPath: "activeFlag", cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController as! NSFetchedResultsController<Vehicles>
}()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
do {
try self.fetchedResultsController.performFetch()
}
catch {
let fetchError = error as NSError
print("\(fetchError), \(fetchError.userInfo)")
}
tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
if let sections = fetchedResultsController.sections {
return sections.count
}
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController.sections {
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
return 0
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor(red: 55/255, green: 120/255, blue: 250/255, alpha: 1)
guard let sectionInfo = fetchedResultsController.sections?[section] else {
return view
}
let title = UILabel()
title.font = UIFont.boldSystemFont(ofSize: 16)
title.textColor = .white
title.text = sectionInfo.name == "1" ? "Active" : "Inactive"
view.addSubview(title)
title.translatesAutoresizingMaskIntoConstraints = false
title.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
title.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16).isActive = true
return view
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "vehicleCell", for: indexPath)
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor.clear
}
else {
cell.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2)
}
let vehicle = fetchedResultsController.object(at: indexPath)
cell.textLabel!.text = vehicle.vehicleDesc
return cell
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deleteItemIndexPath = indexPath
let vehicle = fetchedResultsController.object(at: indexPath)
confirmDelete(itemToDelete: vehicle.vehicleDesc!)
}
}
func confirmDelete(itemToDelete: String) {
let alert = UIAlertController(title: "Delete Vehicle", message: "Are you sure you want to delete vehicle \(itemToDelete)", preferredStyle: .actionSheet)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: handleDeleteItem)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: cancelDeleteItem)
alert.addAction(deleteAction)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
func handleDeleteItem(alertAction: UIAlertAction!) -> Void {
if let indexPath = deleteItemIndexPath {
let vehicle = fetchedResultsController.object(at: indexPath)
let route = dao.getRouteForVehicle(vehicleId: vehicle.vehicleId!)
if let _ = route {
vehicle.activeFlag = false
}
else {
GlobalVariables.getContext().delete(vehicle)
}
}
}
func cancelDeleteItem(alertAction: UIAlertAction!) {
deleteItemIndexPath = nil
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.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 {
tableView.insertRows(at: [indexPath], with: .fade)
}
break;
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.reloadData()
}
break;
// case .update:
// if let indexPath = indexPath {
// let cell = tableView.cellForRow(at: indexPath)
// configureCell(cell, atIndexPath: indexPath)
// }
// break;
case .move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .fade)
}
break;
default:
break
}
}
// MARK: - segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "editVehicleSegue" {
if let vehicleEditViewController = segue.destination as? VehicleEditViewController {
if let indexPath = tableView.indexPathForSelectedRow {
let vehicle = fetchedResultsController.object(at: indexPath)
vehicleEditViewController.vehicle = vehicle
vehicleEditViewController.tableView = tableView
}
}
}
}
// // MARK: - Actions
//
// @IBAction func btnAdd_ACTION(_ sender: UIBarButtonItem) {
// var emptyFound = false
// for i in 0..<vehicles.count {
// let vehicle = vehicles[i]
// if vehicle.isEmpty {
// emptyFound = true
// break
// }
// }
// if !emptyFound {
// vehicles.append("")
// tableView.reloadData()
// }
// }
}
Run Code Online (Sandbox Code Playgroud)
When you remove the last row from a section, you need to let the table view that the whole section has been removed.
You can do this by implementing
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange sectionInfo: NSFetchedResultsSectionInfo,
atSectionIndex sectionIndex: Int,
for type: NSFetchedResultsChangeType) {
let section = IndexSet(integer: sectionIndex)
switch type {
case .delete:
tableView.deleteSections(section, with: .automatic)
case .insert:
tableView.insertSections(section, with: .automatic)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2835 次 |
| 最近记录: |