删除行时TableView“无法识别的选择器发送到实例”错误

Posted

技术标签:

【中文标题】删除行时TableView“无法识别的选择器发送到实例”错误【英文标题】:TableView "unrecognized selector sent to instance" error when deleting row 【发布时间】:2014-10-29 07:46:31 【问题描述】:

我有一个按钮可以删除它所在的单元格。数据模型工作正常,tableView.reloadData() 不会导致错误。但是,当我使用 tableView.deleteRowsAtIndexPaths(..) 时,会发生崩溃,告诉我以下信息:

-[__NSCFNumber row]: unrecognized selector sent to instance 0xb000000000000003
2014-10-29 03:37:08.999 SampleApp[4915:82542] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber row]: unrecognized selector sent to instance 0xb000000000000003'

指示发生这种情况的代码如下所示。我感觉它与我的通知有关,但我不知道为什么。在发布通知时,我尝试使用 nil 作为 object 的参数,但这并没有什么不同。我不明白为什么 tableView.reloadData() 会起作用,而替代方法不会。我怎样才能阻止这种情况发生?

GoalTableViewCell 继承自 UITableViewCell 的类(摘录)

@IBAction func deleteButtonTapped(sender: AnyObject)  //IBAction is connected to a delete button within the cell.
        let index = self.indexInTable //indexInTable is an Int property that tracks where the cell is located in the tableView. It is updated using cellForRowAtIndexPath(..)
        var userInfo = ["index" : index]
        NSNotificationCenter.defaultCenter().postNotificationName("DeletedGoal", object: self, userInfo: userInfo)
    

GoalsTableViewController 继承自 UIViewController 的类(其中有一个 tableView)(摘录)

    func deletedGoal(notification : NSNotification) 
        if (notification.name == "DeletedGoal") 
            var userInfo = notification.userInfo!
            var index = userInfo["index"] as Int //this is returning the proper index.

            goalsArray.removeAtIndex(index)
            saveGoals(goalsArray)
            //self.tableView.reloadData() //this works.
            self.tableView.deleteRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimation.Fade) //this causes error

        
    

编辑:我更正了代码(非常感谢各位),但遇到了一个新错误。我可能会为此提出一个新问题:在连续删除更多单元格后,我最终会崩溃,告诉我 indexPath 太高。我猜 cellForRowAtIndexPath(..) 是问题所在,它不会标记单元格的 indexInTable 属性,除非发生滚动(?)

    //correct code
   func deletedGoal(notification : NSNotification) 
            if (notification.name == "DeletedGoal") 
                var userInfo = notification.userInfo!
                //var cell = userInfo["cell"] as GoalTableViewCell
            var index = userInfo["index"] as Int

            println(index)
            goalsArray.removeAtIndex(index)
            saveGoals(goalsArray)
            let indexPath = NSIndexPath(forRow:index,inSection:0)
            self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            //self.tableView.reloadData()

        
    

【问题讨论】:

我建议您打开另一个问题,但问题是您将 indexPaths 存储在单元格中 - 当您删除一行时,所有这些 indexPaths 现在都无效(因为第 5 行现在是第 4 行,所以在)。出于兴趣,你为什么不使用内置的表格编辑功能(滑动删除) - 然后你会得到委托回调告诉你哪一行被删除 这是因为我的 tableView 在 pageViewController 中,所以如果我让他们用户滑动删除,就会导致页面之间滑动出现问题。我可以只使用一个编辑按钮并使用该功能。感谢您的帮助! 【参考方案1】:

如果您查看异常消息,您将看到 [__NSCFNumber row],它告诉您尝试在 NSCFNumber(这是 NSNumber 的内部类)上调用 row 方法 - 这不会有一个行方法。

现在看看self.tableView.deleteRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimation.Fade) - 方法名称告诉您(或者您可以阅读文档)它需要NSIndexPaths 的数组而不是NSNumbers

所以,你想说的是

self.tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow:index inSection:0)], withRowAnimation:UITableViewRowAnimation.Fade)

这是假设您的表只有一个部分。如果它有多个部分,那么您将需要跟踪单元格中的部分编号以及行。您可以通过将您存储的属性更改为 indexPath 而不是 IndexPath.row 来做到这一点。

那你可以说

@IBAction func deleteButtonTapped(sender: AnyObject)  //IBAction is connected to a delete button within the cell.
        let index = self.indexInTable //indexInTable is an NSIndexPath property that tracks where the cell is located in the tableView. It is updated using cellForRowAtIndexPath(..)
        var userInfo = ["index" : index]
        NSNotificationCenter.defaultCenter().postNotificationName("DeletedGoal", object: self, userInfo: userInfo)
    

func deletedGoal(notification : NSNotification) 
    if (notification.name == "DeletedGoal") 
        var userInfo = notification.userInfo!
        var index = userInfo["index"] as NSIndexPath

        goalsArray.removeAtIndex(index.row)
        saveGoals(goalsArray)
        //self.tableView.reloadData() //this works.
        self.tableView.deleteRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimation.Fade) //this causes error

    

【讨论】:

【参考方案2】:

问题很可能是var index 设置为typeof Int。

但是,deleteRowsAtIndexPaths 方法需要 NSIndexPath 类型的对象,因为在内部它将调用传递路径上的选择器行。

在您的情况下,选择器是在 Int 上调用的,它不响应行选择器。首先创建一个索引路径作为你的行,你会很高兴的。 :D

【讨论】:

以上是关于删除行时TableView“无法识别的选择器发送到实例”错误的主要内容,如果未能解决你的问题,请参考以下文章

UITableView,无法识别的选择器发送到实例

使用 UILocalizedIndexedCollat​​ion 在 Swift 4.2 中创建 tableView 部分索引时出现错误“无法识别的选择器发送到实例”

无法识别的选择器发送到实例

ContiguousArrayStorage 行无法识别的选择器发送到实例

Swift 2,无法识别的选择器发送到 UIAlertController 的实例

控制器视图停止动画无法识别的选择器发送到实例