繁体   English   中英

使用 NSFetchedResultsController 插入/删除 UITableView

[英]Inserting/Deleting into UITableView with NSFetchedResultsController

我对 Swift 开发相对较新,并且在使用 NSFetchedResultsController 时,我正在努力用新实体 (CoreData) 更新 UITableView。

我在互联网上搜索并遵循了各种教程,但是尽管遵循了它们,但当我将其转换为我的情况时,出现了一些问题,经过数小时的摸索,我似乎看不出有什么问题。

我希望将数据存储在 tableView 中,允许向左滑动以删除,并有一个用于为表创建新数据的表单。 我有插入工作,但没有删除,现在有删除工作,但没有插入。

我有上下文变量并像这样收集我的数据:

func loadData() {
    let request = MyData.fetchRequest() as NSFetchRequest<MyData>
    let sort = NSSortDescriptor(key: #keyPath(MyData.name), ascending: true)
    request.sortDescriptors = [sort]

    do {
        myResults = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: #keyPath(MyData.name), cacheName: nil)
        try myResults.performFetch()

    } catch let error as NSError {
        print("Could not fetch \(error), \(error.userInfo)")
    }
    myTableView.reloadData()
}

我正在尝试添加数据(当用户点击按钮时),如下所示:

let newData = MyData(entity: MyData.entity(), insertInto: context)
                newData.name = newName
                newData.colour = Int16(newDataPicker.selectedRow(inComponent: 0))
                newData.dataID = dataID
appDelegate.saveContext()
loadData()

这没有问题,但是每次我尝试删除时,我都会因为 model 数据和 TableView 不同步而崩溃。 经过大量研究,我实现了 NSFetchedResultsControllerDelegate,如下所示:

extension ViewController: NSFetchedResultsControllerDelegate {
    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        self.myTableView.beginUpdates()
    }
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .delete:
            self.myTableView.deleteRows(at: [indexPath! as IndexPath], with: .fade)
//        case .insert:
//            self.myTableView.insertRows(at: [newIndexPath! as IndexPath], with: .fade)
        default:
            break
        }
    }
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        self.myTableView.endUpdates()
    }
}

现在可以让我精美地删除。 不幸的是,我现在无法添加,因为这会使我的应用程序因Invalid update错误而崩溃。

我已经尝试使用 NSFetchedResultsControllerDelegate 来处理插入,使用context.insert()但这也会导致崩溃。

请有人能告诉我我犯了什么愚蠢的错误吗? 非常感谢!

您正在执行太多不必要的步骤,这会混淆NSFetchedResultsController的功能。

删除和插入记录后,controller 在保存上下文后立即自动更新 UI

首先,按照 CoreData 模板中的建议创建一个NSFetchedResultsController实例作为惰性实例化属性并设置委托。

lazy var fetchedResultsController: NSFetchedResultsController<MyData> = {

    let request = MyData.fetchRequest() as NSFetchRequest<MyData>
    let sort = NSSortDescriptor(key: #keyPath(MyData.name), ascending: true)
    request.sortDescriptors = [sort]
    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: #keyPath(MyData.name), cacheName: nil)
    aFetchedResultsController.delegate = self
    do {
        try aFetchedResultsController.performFetch()
    } catch {
        print(error)
    }
    return aFetchedResultsController
}()

loadData替换为

func loadData()
{
    do {
        try fetchedResultsController.performFetch()
        tableView.reloadData()
    } catch {
        print(error)
    }
}

并在didChange方法中实现所有类型

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .insert: tableView.insertRows(at: [newIndexPath!], with: .fade)
    case .delete: tableView.deleteRows(at: [indexPath!], with: .fade)
    case .update: tableView.reloadRows(at: [indexPath!], with: .automatic)
    case .move: tableView.moveRow(at: indexPath!, to: newIndexPath!)
    @unknown default:
        fatalError("New case in controller:didChange:at:for:")
    }
}

如果 controller 也应该管理部分实施

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {

    switch type {
    case .insert: tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
    case .delete: tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
    default: return
    }
}

现在在上下文中插入一条记录或从上下文中删除一条记录。 然后保存上下文——没有别的——获取结果 controller 执行 rest。 不要调用loadData也不要额外重新加载表视图。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM