NSInternalInconsistencyException:使用tableview CoreData

时间:2015-08-28 19:18:22

标签: swift uitableview core-data rows nsexception

我使用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

}

2 个答案:

答案 0 :(得分:0)

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

        var personToDelete = NSManagedObject()

以及您在commitEditingStyle函数中声明的局部变量:

        let personToDelete = results[deleteRow] as! NSManagedObject

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

立即解决方案是使用函数中的属性,而不是局部变量:只需删除let

        personToDelete = results[deleteRow] as! NSManagedObject

但我还建议您重新考虑您的方法:您正在重复相同的提取。如果所有数据源方法都是相同的,那么在首次构建表视图时,每当单元格被滚动到视图中时,无论何时敲击单元格等,它都将重复多次。这在性能方面将是昂贵的。您应该进行一次fetch(可能在viewDidLoad中),将结果存储在数组属性中,并将其用于表视图数据源方法。或者,也许最好使用NSFetchedResultsController:它非常有效,并且在添加或删除对象时有更新表视图的样板代码。

答案 1 :(得分:0)

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