Сохранение отредактированного объекта Core Data не сохраняется - PullRequest
0 голосов
/ 28 января 2019

У меня есть TableView с несколькими разделами, который заполняется сущностями (называемыми «Элемент») с использованием инфраструктуры Core Data.В методе делегата cellForRowAt я вызываю обратный вызов, который вызывается, когда пользователь нажимает клавишу «Ввод».Этот обратный вызов должен сохранить текст, который они только что набрали в текстовом поле ячейки, в базовую модель данных, а затем добавить новую пустую ячейку прямо под ней.

Все это работает, за исключением случаев, когда раздел пуст и вы пытаетесьустановить item.name равным textfield.text.Если я добавлю несколько элементов в этот раздел, он сохранит все ячейки, которые я только что создал и добавил в модель данных, за исключением самой первой.

Сначала я обновлял элемент, а затем сохранял контекст, ноЯ получаю сообщение об ошибке «ошибка: изменение управляемого объекта после его удаления из контекста».См. Приведенный ниже код.

    /// Customize the contents of the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: homeCellId, for: indexPath) as! HomeTableViewCell
    cell.delegate = self
    let item = items[indexPath.section][indexPath.row]

    cell.nameText.text = item.name

    /// Called when user hits Enter on the keyboard
    /// This allows them to enter a new item
    cell.addNewCell = { [weak self] newTitle in
        guard let `self` = self else {return} // Capture self

        if cell.nameText.text != "" {

            let newTitle: String = cell.nameText.text! // Grab the name øf the item the user just entered
            let itemToUpdate = self.items[indexPath.section][indexPath.row] // Grab the item they typed

            itemToUpdate.name = cell.nameText.text
            self.saveContext()


            // Create reference to indexpath below the existing cell
            let newIndexPath = IndexPath(row: indexPath.row+1, section: indexPath.section) // Set the indexPath to the cell below
            // Create new dummy item
            let newPlaceholderItem = self.coreDataManager.addItem(toCategory: self.categories[indexPath.section], withItemName: "")
            // Add dummy item to tableview array
            self.items[indexPath.section].append(newPlaceholderItem)
            self.tableView.insertRows(at: [newIndexPath], with: .automatic) // Insert it into the tableView
        } else {
            print("Can not add new cell since current cell is empty")
        }
    }

    return cell
}

После долгих поисков в Google я обнаружил, что решением вышеупомянутой ошибки является использование executeBackgroundTask (), показанного ниже.

/// Customize the contents of the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: homeCellId, for: indexPath) as! HomeTableViewCell
    cell.delegate = self
    let item = items[indexPath.section][indexPath.row]

    cell.nameText.text = item.name

    /// Called when user hits Enter on the keyboard
    /// This allows them to enter a new item
    cell.addNewCell = { [weak self] newTitle in
        guard let `self` = self else {return} // Capture self


        if cell.nameText.text != "" {

            let newTitle: String = cell.nameText.text! // Grab the name øf the item the user just entered
            let itemToUpdate = self.items[indexPath.section][indexPath.row] // Grab the item they typed

            let container = (UIApplication.shared.delegate as! AppDelegate).persistentContainer // Grab the persistent container

            container.performBackgroundTask { (context) in
                // Make sure the object isn't null
                guard let queueSafeItem = context.object(with: itemToUpdate.objectID) as? Item else {
                    print("Error, could not update item.")
                    return
                }

                queueSafeItem.name = newTitle // Update the title of the item

                // Save the change that the user made to the cell he just edited
                do {
                    print("Saving context after modifying item")
                    try context.save()
                } catch {
                    print("Error saving when creating new cell: \(error)")
                }
            }

            // Create reference to indexpath below the existing cell
            let newIndexPath = IndexPath(row: indexPath.row+1, section: indexPath.section) // Set the indexPath to the cell below
            // Create new dummy item
            let newPlaceholderItem = self.coreDataManager.addItem(toCategory: self.categories[indexPath.section], withItemName: "")
            // Add dummy item to tableview array
            self.items[indexPath.section].append(newPlaceholderItem)
            self.tableView.insertRows(at: [newIndexPath], with: .automatic) // Insert it into the tableView
        } else {
            print("Can not add new cell since current cell is empty")
        }
    }

    return cell
}

1 Ответ

0 голосов
/ 29 января 2019

После некоторой отладки кажется, что я не правильно сохранил "фиктивные" ячейки и мне пришлось переформатировать некоторый код.Никаких ошибок в конце Xcode или Swift - просто обычная ошибка программиста.

...