在Swift中向选择器传递参数

10

我正在开发一个应用程序,用于跟踪大学课程阅读任务。每个ReadingAssignment包括一个Bool值,指示读者是否完成了任务。ReadingAssignments被收集到WeeklyAssignment数组中。我希望用户能够触摸标签并显示选中标记以表示已完成任务。我也希望这种触摸还更新.checked属性为true,以便我可以保留数据。 因此,我尝试让gestureRecognizer调用labelTicked()方法。这个方法有效并在控制台上打印输出。但是,当我尝试传递参数assignment时,它会编译,但在触摸时崩溃,出现“未识别的选择器”错误。我已经阅读了这里可以找到的所有主题,并没有找到解决方案。他们都说“:”表示具有参数的选择器,但仍然无法实现。 你能看出我做错了什么吗?

func configureCheckmark(cell: UITableViewCell, withWeeklyAssignment assignment: WeeklyAssignment) {

    let checkLabel = cell.viewWithTag(1002) as! UILabel
    checkLabel.userInteractionEnabled = true
    let gestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("labelTicked:assignment"))
    checkLabel.addGestureRecognizer(gestureRecognizer)

}

@objc func labelTicked(assignment: WeeklyAssignment) {

    assignment.toggleCheckmark()

        if assignment.checked {
            label.text = "✔︎"
        } else {
            label.text = ""
        }
}

我也希望能够传递UILabel checkLabel,以便在labelTicked()方法中更新它。 感谢你的帮助。

2个回答

23

这里有两个不同的问题:

  1. 选择器的语法有误;冒号:并未标记参数部分的开头,仅仅表示该函数需要参数。因此,tap手势识别器应该初始化为UITapGestureRecognizer(target: self, action: "labelTicked:")。很容易解决,这是好消息。

  2. 坏消息是:即使语法完美,你设置的方式也无法正常工作。你的tap手势识别器无法将WeeklyAssignment对象作为参数传递。事实上,它根本不能传递任何自定义参数。至少不是那样传递的。

但是,你可以将它传递到sender中(通常是手势识别器所附加的视图)。你可以通过改变你的方法来获取它:

func labelTicked(sender: AnyObject) {

(请注意,如果您确切地知道要期望什么,AnyObject 可以声明为更具体的类型。)

通过发送方,理论上现在可以推断出已经点击了哪个标签,该标签对应的数据实体以及该实体的checked属性的状态。但我认为这会很快变得非常复杂。

看起来简单的事情变得复杂通常是我们应该退一步寻找更好的解决方案的好迹象。

我建议此时放弃整个GestureRecognizer方法,而是利用表视图中的每个单元格已经默认带有自己的“轻拍识别”功能这一事实:即表视图的代理的didSelectRowAtIndexPath:方法。在那里,您可以轻松使用提供的NSIndexPath从数据源检索对应的模型实体以根据需要读取和修改其参数。通过cellForRowAtIndexPath:,您可以获取正确单元格的引用并相应地更改其内容。


适用于 Swift 3 的更新:

随着Swift语言的发展,使用基于字符串的选择器(例如"labelTicked:")现在被标记为已弃用,因此我认为提供一小部分更新是合适的。

使用更现代的语法,您可以这样声明函数:

@objc func labelTicked(withSender sender: AnyObject) {

您可以像这样初始化手势识别器,并使用#selector

UITapGestureRecognizer(target: self, action: #selector(labelTicked(withSender:)))

那最初是我设置的方式。但我正在使用didSelectRowAtIndexPath:来执行一个segue,将它们带到显示阅读任务详细信息的视图中。是否可能(像在sprite上)将单元格分割,使得在单元格前1/4处触摸执行checkmark方法,在其余部分触摸则执行segue? - Cyrus Price

4

该函数的正确选择器是labelTicked:。此外,您可以直接使用字符串作为选择器。因此:

let gestureRecognizer = UITapGestureRecognizer(target: self, action: "labelTicked:")

但是当识别器触发时,您无法安排将任意对象传递给方法。更好的方法是创建一个UITableViewCell的子类,我们称其为AssignmentCell。给子类一个assignment属性,并将labelTicked:方法移动到AssignmentCell中。
如果您已经在故事板中设计了单元格,可以在故事板中直接向标签添加一个轻击识别器,并将识别器与单元格的labelTicked:方法连接在故事板中。
在您的表视图数据源的tableView(_:cellForRowAtIndexPath:)中,在您弹出单元格后,将其assignment属性设置为该行的作业。

感谢您的评论,Rob。我仍在学习编程,所以我对您所说的有基本的理解(我想)。那么,我的WeeklyAssignment类可以继承UITableViewCell吗?您知道吗,我想我明白您在说什么,但不知道如何实现您所描述的内容。 - Cyrus Price

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接