Проблема с NSFetchedResultsController


#1

Добрый день

Пытаюсь обновить свою таблицу при помощи NSFetchedResultsController. Код выглядит следующим образом:

func controllerWillChangeContent(_ controller: NSFetchedResultsController) {
self.tableView.beginUpdates()
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    tableView = self.tableView
    switch type {
    case .insert:
        print("insert")
            tableView.insertRows(at: [IndexPath(row: enabledArray.count, section: 0)], with: .automatic)
    case .update:
        print("update")
        if let indexPath = indexPath {
            switch indexPath.row {
            case lastCell:
                let cell = Bundle.main.loadNibNamed("AddAlarmCell", owner: self, options: nil)?.first as! AddAlarmCell
                cell.delegate = self
                cell.selectionStyle = .none
                cell.backgroundColor = UIColor.clear
            default:
                let cell = Bundle.main.loadNibNamed("AlarmCell", owner: self, options: nil)?.first as! AlarmCell
                cell.delegate = self
                cell.selectionStyle = .none
                cell.backgroundColor = UIColor.clear
                cell.daysLbl.text = ""
                if enabledArray[indexPath.row].mondayOn == true{
                    cell.daysLbl.text = "ПН "
                }
                if enabledArray[indexPath.row].tuesdayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"ВТ "
                }
                if enabledArray[indexPath.row].wednesdayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"СР "
                }
                if enabledArray[indexPath.row].thursdayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"ЧТ "
                }
                if enabledArray[indexPath.row].fridayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"ПТ "
                }
                if enabledArray[indexPath.row].saturdayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"СБ "
                }
                if enabledArray[indexPath.row].sundayOn == true{
                    cell.daysLbl.text = cell.daysLbl.text!+"ВС "
                }
                cell.timeLbl.text = enabledArray[indexPath.row].alarmTimeStr
                cell.onOffSwitch.isOn = enabledArray[indexPath.row].alarmOn
            }
        }
    case .move:
        if let indexPath = indexPath {
            tableView.deleteRows(at: [indexPath as IndexPath], with: .automatic)
        }
        if let newIndexPath = newIndexPath {
            tableView.insertRows(at: [newIndexPath as IndexPath], with: .automatic)
        }
    case .delete:
        if let indexPath = indexPath {
            tableView.deleteRows(at: [indexPath as IndexPath], with: .automatic)
        }
    }
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    self.tableView.endUpdates()
}

Все изменения отрабатываются корректно, кроме функции добавления: при попытке использовать insert он выдает ошибку :

CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

Я так понимаю, что дело в неправильной индексации размера массива, но где именно это может сбоить - не очень понятно. Нет ли у кого идей, в какой области надо копать?


#2

При добавлении надо использовать newIndexPath


#3

Переписал в такой вид:

case .insert:
            print("insert")
            guard let indexPath = newIndexPath else {break}
            tableView.insertRows(at: [indexPath], with: .none)

Не помогло


#4

На всякий случай так же прикладываю функции формирования таблицы:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if enabledArray.count == 0 {
        return 1
    } else if enabledArray.count < 20{
        lastCell = enabledArray.count
        return lastCell+1
    } else {
        lastCell = enabledArray.count
        return lastCell
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    switch indexPath.row {
        case lastCell:
            let cell = Bundle.main.loadNibNamed("AddAlarmCell", owner: self, options: nil)?.first as! AddAlarmCell
            cell.delegate = self
            cell.selectionStyle = .none
            cell.backgroundColor = UIColor.clear
            return cell
        default:
            let cell = Bundle.main.loadNibNamed("AlarmCell", owner: self, options: nil)?.first as! AlarmCell
            cell.delegate = self
            cell.selectionStyle = .none
            cell.backgroundColor = UIColor.clear
            cell.daysLbl.text = ""
            if enabledArray[indexPath.row].mondayOn == true{
                cell.daysLbl.text = "ПН "
            }
            if enabledArray[indexPath.row].tuesdayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"ВТ "
            }
            if enabledArray[indexPath.row].wednesdayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"СР "
            }
            if enabledArray[indexPath.row].thursdayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"ЧТ "
            }
            if enabledArray[indexPath.row].fridayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"ПТ "
            }
            if enabledArray[indexPath.row].saturdayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"СБ "
            }
            if enabledArray[indexPath.row].sundayOn == true{
                cell.daysLbl.text = cell.daysLbl.text!+"ВС "
            }
            cell.timeLbl.text = enabledArray[indexPath.row].alarmTimeStr
            cell.onOffSwitch.isOn = enabledArray[indexPath.row].alarmOn
            return cell
    }
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    switch indexPath.row {
    case lastCell:
        return 100
    default:
        return 120
    }
}

#5

А что это так много вопросов на эту тему?четветый за месяц…


#6

Ну вот и весь ответ! Я вас прошу, возьмите бумажку, карандаш и подумайте, нарисуйте схемку и разберитесь как что такое индекс, откуда он берётся и как обновляется!


#7

Я понимаю, что по факту XCode описывает проблему, но мне непонятна Ее причина и способы решения.

Я пробовал задать IndexPath для сектора 0 меньшим, большим или равным количеству элементов в массиве из которого заполняю ячейку. Но эффекта это не принесло. Честно говоря, я не до конца понимаю почему он вываливается из рамок IndexPath, а если он это делает, потому что так задумано для расширения массива - почему он сваливается.

Что мог про IndexPath прочитал, документацию про него тоже вроде изучил. Но этот момент все ещё непонятен. А ещё непонятно, почему он сваливается именно так, а Out of range’м например. В чем разница?


#8

У меня было предположение, кстати, что это все валится из-за другого типа последней ячейки, кстати. Мол не может вписать данные, т.к. ее формат отличается.
Но я не до конца уверен.


#9

Снимаю вопрос.

Выяснилось, что в функции добавлении будильника я прописал tableView.reloadData(), что вызывало проблемы.
На будущее всем, кто столкнется с той же проблемой: проверьте свой код еще раз, использовать begin/endupdates с reloadData одновременно не стоит. Выбрать нужно что-то одно.


#10

Я уже много раз писал и напишу еще: НЕ стоит перегружать таблицу на основе данных которые еще грузиться! загрузка процесс долгий! Загрузили -> Записали туда, на основе чего строиться таблица, перегрузили таблицу!


#11

Спасибо!!!