我有一個 UITableView,它使用基于 CoreData 屬性的 NSFetchedResultsController 填充它的單元格,該屬性isForConverter是 Bool 并且應該是真實的才能顯示。isForConverter在另一個 ViewController 中設定狀態。當我想從 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, 提交editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
然后一切正常。但是洗掉影片真的是又快又煩。另外根據檔案,我不應該tableView.reloadData()與 NSFetchedResultsController 一起使用...
如何解決這種行為?
更新:
看來我發現了那次崩潰的原因。這就是我的 print() 嘗試給出的:SCREENSHOT。什么是pickCurrency:這是一個自定義型別Currency 的全域變數,我創建它以接收其屬性currentValue(Double,87.88)。我只需要從選擇的編輯單元格中獲取該值。在我在 cellForRowAt() 使用該值進行計算之后,計算結果將填充所有其他現在不在編輯模式下的單元格。
我在 textFieldDidBeginEditing() 中定義了pickCurrency,因為在那里我收到了我選擇編輯的確切行貨幣:
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 中使用它的值來計算所有其他單元格的值,基于 pickCell 值和我放在 activeCell 的 textField 中的數字:
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()?
uj5u.com熱心網友回復:
我不確定這是否可行,但它似乎太長了,不能成為評論,所以試試下面的。
最初我告訴你可以使用標簽來識別一個特定的視圖,這有利于快速和簡單的實作,但是當我們現在擁有的行被移動/洗掉時,使用標簽進行管理將非常困難,因為你必須不斷更新它們。
對于靜態表視圖,它們很好,但如果你的行會改變,那么像委托/觀察者這樣更復雜的模式可能會更好。
無論如何,我認為現在可以幫助您的情況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 = ""
}
}
這有幫助嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/427929.html
標籤:迅速 合适的视图 uikit nsfetchedresults 控制器
