NSInternalInconsistencyException: Invalid Update using table



我使用tableView来显示人员列表。我试图添加一个警报,以确认用户实际上想要删除的人,并防止错误。但是,当我试图删除与CoreData一起存储的人员时,重新加载视图似乎有问题。我得到了这个例外:Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

编辑和删除功能:

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        // Delete the row from the data source
        var deleteRow = indexPath.row
        indexPathforDelete = indexPath
        let entityDescription = NSEntityDescription.entityForName("People", inManagedObjectContext: managedObjectContext!)
        let request = NSFetchRequest()
        request.entity = entityDescription
        var error: NSError?
        var objects = managedObjectContext?.executeFetchRequest(request, error: &error)
        if let results = objects {
            let personToDelete = results[deleteRow] as! NSManagedObject
            let firstName = personToDelete.valueForKey("firstName") as! String
            let lastName = personToDelete.valueForKey("lastName") as! String
            var message = "Are you sure you would like to delete (firstName) (lastName)?nThis will permanentaly remove all records of "
            if(personToDelete.valueForKey("gender") as! String == "Male"){
                message = "(message)him."
            }
            else{
                println(personToDelete.valueForKey("gender") as! String)
                message = "(message)her."
            }
            var deleteAlert : UIAlertView = UIAlertView(title: "Delete (firstName) (lastName)", message: message, delegate: self, cancelButtonTitle: "Cancel")
            deleteAlert.addButtonWithTitle("Delete")
            deleteAlert.show()
        }
        save()
    } else if editingStyle == .Insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }    
}

AlertView响应功能:

func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int){
    if(buttonIndex == 1){
        managedObjectContext?.deleteObject(personToDelete)
        tableView.deleteRowsAtIndexPaths([indexPathforDelete], withRowAnimation: .Fade)
        save()
    }
    setEditing(false, animated: true)
    self.navigationItem.leftBarButtonItem = nil
}

tableView行数函数:

var personToDelete = NSManagedObject()
var indexPathforDelete = NSIndexPath()
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete method implementation.
    // Return the number of rows in the section.
    let entityDescription = NSEntityDescription.entityForName("People", inManagedObjectContext: managedObjectContext!)
    let request = NSFetchRequest()
    request.entity = entityDescription
    var error: NSError?
    var objects = managedObjectContext?.executeFetchRequest(request, error: &error)
    let results = objects
    println("Results Count: (results!.count)")
    return results!.count
}

认为问题在于您有两个名称为propertyToDelete的变量:您声明并初始化空白NSManagedObject的属性:

        var personToDelete = NSManagedObject()

和在commitEditingStyle函数中声明的局部变量:

        let personToDelete = results[deleteRow] as! NSManagedObject

就是这个局部变量,您可以将结果数组中的对象赋值给它。但是,当函数完成时,这个局部变量将被销毁,并且AlertView操作正在删除属性所指向的对象。(我犹豫的原因是,我希望你的上下文抛出一个错误,当它试图删除一个从未注册过的对象)。注意,相比之下,您只有一个名为indexPathforDelete的变量。当AlertView操作运行时,它会保存正确的值,因此tableView会删除正确的行。这就是得到错误的原因:它删除了一行,但随后发现(因为没有对象被删除)它仍然有与以前相同的行数。

直接的解决方案是在函数中使用该属性,而不是使用局部变量:只需删除let:
        personToDelete = results[deleteRow] as! NSManagedObject

但我也建议你重新考虑你的方法:你在重复同样的获取。如果所有的数据源方法都做同样的事情,那么当表视图第一次构建时,当一个单元格被滚动到视图中时,当一个单元格被点击时,都会重复很多次。就性能而言,这将是代价高昂的。相反,您应该进行一次获取(可能在viewDidLoad中),将结果存储在array属性中,并将其用于表视图数据源方法。或者,也许更可取的是,使用NSFetchedResultsController:它非常有效,并且当添加或删除对象时,有用于更新表视图的样板代码。

tableView:commitEditingStyle:forRowAtIndexPath:的文档说:"你不应该在这个方法的实现中调用setEditing:animated:。如果出于某种原因,您必须在延迟之后使用performSelector:withObject:afterDelay:方法来调用它。"

最新更新