NSFetchedResultsController error: 'no object at index in section at index 0'



我有一个UITableView,它使用基于CoreData属性isForConverter的NSFetchedResultsController填充单元格,该属性为Bool,应该为true才能显示。在另一个ViewController中设置isForConverter状态。当我想从UITableView中删除一些单元格时,在访问未删除的单元格后,我收到错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'no object at index 5 in section at index 0'

有一个GIF有问题:https://cln.sh/M1aI9Z

我的删除单元格的代码。我不需要从数据库中删除它,只需将其isForConverter从true更改为false:

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let currency = fetchedResultsController.object(at: indexPath)
currency.isForConverter = false
coreDataManager.save()
}
}

NSFetchedResultsController设置和委托:

func setupFetchedResultsController() {
let predicate = NSPredicate(format: "isForConverter == YES")
fetchedResultsController = coreDataManager.createCurrencyFetchedResultsController(with: predicate)
fetchedResultsController.delegate = self
try? fetchedResultsController.performFetch()
}
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 .update:
if let indexPath = indexPath {
tableView.reloadRows(at: [indexPath], with: .none)
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.moveRow(at: indexPath, to: newIndexPath)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .none)
}
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .none)
}
default:
tableView.reloadData()
}
}
}

我注意到,如果我只是将tableView.reloadData()添加到:

tableView(_tableView:UITableView,提交编辑样式:UITableViewCell.EditingStyle,用于RowAt indexPath:indexPath(

然后一切都很好。但是删除动画真的很快而且很麻烦。此外,根据文档,我不应该将tableView.reloadData()与NSFetchedResultsController一起使用。。。

如何纠正这种行为?

更新:

我似乎发现了那次车祸的原因。这就是我的print((尝试给出的结果:屏幕截图。什么是pickedCurrency:这是一个自定义类型Currency的全局变量,我创建它是为了接收其属性currentValue(Double,87.88(。我只需要picked-to-edit单元格中的值。在cellForRowAt((中使用该值进行计算后,计算结果将填充所有其他现在不处于编辑模式的单元格。

我在textFieldDidBeginEdit((中定义了pickedCurrency,因为在那里我收到了我选择编辑的货币的确切行:

func textFieldDidBeginEditing(_ textField: UITextField) {
pickedCurrency = fetchedResultsController.object(at: IndexPath(row: textField.tag, section: 0))
numberFromTextField = 0
textField.textColor = UIColor(named: "BlueColor")
textField.placeholder = "0"
textField.text = ""
}

然后使用它在cellForRowAt中的值,根据pickedCell的值和我在activeCell:的文本字段中输入的数字来计算所有其他单元格的值

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell

let currency = fetchedResultsController.object(at: indexPath)
cell.flag.image = currencyManager.showCurrencyFlag(currency.shortName ?? "notFound")
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
cell.numberTextField.tag = indexPath.row
cell.numberTextField.delegate = self

if let number = numberFromTextField, let pickedCurrency = pickedCurrency {
cell.numberTextField.text = currencyManager.performCalculation(with: number, pickedCurrency, currency)
}
return cell
}

似乎当我删除了很多单元格,然后点击随机单元格进行编辑时,它并没有更新其IndexPath(row: textField.tag, section: 0)。。。

也许有一种方法可以接收我在cellForRowAt()中选择编辑的Currency对象?

我不确定这是否有效,但它似乎太长了,不能作为注释,所以请尝试下面的内容。

最初,我告诉你可以使用标记来识别特定的视图,这对于快速简单的实现来说很好,但当行像我们现在这样被移动/删除时,使用标记将非常困难,因为你必须不断更新它们。

对于静态表视图,它们很好,但如果您的行会发生更改,那么像delegate/obstator这样更复杂的模式可能会更好。

无论如何,我认为目前在textFieldDidBeginEditing中可以帮助您的情况的是停止使用标签来获取索引路径,并从所点击的内容中获取索引路径。

我仍然认为也许委托模式更好,但这可能对你有用:

func textFieldDidBeginEditing(_ textField: UITextField) {
// Get the coordinates of where we tapped in the table
let tapLocation = textField.convert(textField.bounds.origin,
to: tableView)

if let indexPath = self.tableView.indexPathForRow(at: tapLocation)
{
// don't use tag of textfield anymore
pickedCurrency
= fetchedResultsController.object(at: IndexPath(row: indexPath,
section: 0))

numberFromTextField = 0
textField.textColor = UIColor(named: "BlueColor")
textField.placeholder = "0"
textField.text = ""
}
}

这有帮助吗?

相关内容

最新更新