TableView с isEditing = true и CoreData. Как правильно настроить?

swift
xcode
ios
swift3

#1

Всем привет. Я новичок. Решил написать простенькое приложение на основе TableView. В каждой ячейке есть счётчик, который меняет своё значение по нажатию кнопок + и -, которые находятся в той же ячейке. В CoreData создана сущность Counter с одним свойством value. Хочу сделать так, чтоб таблицу можно было редактировать(isEditing = true). Ниже код, в котором я попытался реализовать функционал методами tableView. Перемещение вроде бы проходит нормально, а вот при удалении элемента, таблица ведёт себя не адекватно: меняет значения соседних ячеек, либо приложение падает(видно на прикреплённом видео). Как нужно правильно реализовывать отображение ячеек при isEditing = true используя CoreData? Можно ли как-то использовать для этого NSFetchedResultsControllerDelegate?

https://youtu.be/oaExcob7B2s - видео

import UIKit
import CoreData

class CountersTableViewController: UITableViewController, CounterValueManager, NSFetchedResultsControllerDelegate{
    
    
    
    var fetchController: NSFetchedResultsController<Counter>!
    lazy var context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext
    var counters = [Counter]()
    
    @IBAction func addCounterButton(_ sender: UIBarButtonItem) {
        let counter = Counter(context: context!)
        counter.value = 0
        
        do {
            try context?.save()
            counters.append(counter)
            tableView.reloadData()
        } catch {
            print(error.localizedDescription)
        }
    }

    @IBAction func editButtonPressed(_ sender: UIBarButtonItem) {
        self.isEditing = !self.isEditing
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 100
        tableView.rowHeight = UITableViewAutomaticDimension
        
        let fetchRequest: NSFetchRequest<Counter> = Counter.fetchRequest()
        let sortDescriptor: NSSortDescriptor = NSSortDescriptor(key: "value", ascending: false)
        fetchRequest.sortDescriptors = [sortDescriptor]
        fetchController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context!, sectionNameKeyPath: nil, cacheName: nil)
        //fetchController.delegate = self
        
        do {
            try fetchController.performFetch()
            counters = fetchController.fetchedObjects!
            tableView.reloadData()
        } catch {
            print(error)
        }
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // MARK: - Table view data source
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return counters.count
    }
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? CountersTableViewCell
        cell?.delegate = self
        cell?.increaseButton.tag = indexPath.row
        cell?.decreaseButton.tag = indexPath.row
        cell?.valueLabel.text = String(counters[indexPath.row].value)
        
        return cell!
    }
    
    
    
     // Override to support conditional editing of the table view.
     override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
     // Return false if you do not want the specified item to be editable.
     return true
     }
    
    
    
     // Override to support editing the table view.
     override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
     if editingStyle == .delete {
        let counter = self.counters[indexPath.row]
        context?.delete(counter)
        do {
            try context?.save()
            self.counters.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        } catch {
            print(error.localizedDescription)
        }
     
     } else if editingStyle == .insert {
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
     }
     }
 
    
    
     // Override to support rearranging the table view.
     override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
            let itemToMove = counters[fromIndexPath.row]
            counters.remove(at: fromIndexPath.row)
            counters.insert(itemToMove, at: to.row)
            
            do {
                try context?.save()
                tableView.reloadData()
            } catch {
                print(error.localizedDescription)
            }
            
       
        
        
       
     }
 
    
    
     // Override to support conditional rearranging of the table view.
     override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
     // Return false if you do not want the item to be re-orderable.
     return true
     }
    
    
    // MARK: - FetchedResultsDelegate
    
//    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
//        tableView.beginUpdates()
//    }
    
//    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
//        switch type {
//        case .insert: guard let indexPath = newIndexPath else {break}
//        tableView.insertRows(at: [indexPath], with: .fade)
//        case .delete: guard let indexPath = indexPath else {break}
//        tableView.deleteRows(at: [indexPath], with: .fade)
//        case .update: guard let indexPath = indexPath else {break}
//        tableView.reloadRows(at: [indexPath], with: .fade)
//        tableView.reloadData()
//            
//        default:
//            tableView.reloadData()
//        }
//        counters = controller.fetchedObjects as! [Counter]
//    }
//    
//    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
//        tableView.endUpdates()
//    }
    
    
    
    // MARK: - CounterValueManager funcs
    func increaseAt(index: Int) {
        let counter = counters[index]
        counter.value += 1
        
        do {
            try context?.save()
            tableView.reloadData()
        } catch {
            print(error.localizedDescription)
        }
        
    }
    
    func decreaseAt(index: Int) {
        let counter = counters[index]
        guard counter.value >= 1 else {return}
        counter.value -= 1
        
        do {
            try context?.save()
            tableView.reloadData()
        } catch {
            print(error.localizedDescription)
        }
    }
    
    
    /*
     // MARK: - Navigation
     
     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destinationViewController.
     // Pass the selected object to the new view controller.
     }
     */
    
}

#2

Вы нашли решение? Тоже интересна Ваша тема