【问题标题】:passing parameters to a Selector in Swift将参数传递给 Swift 中的选择器
【发布时间】:2015-10-30 19:31:19
【问题描述】:

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

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() 方法中更新它。 感谢您的帮助。

【问题讨论】:

    标签: ios swift selector uitapgesturerecognizer


    【解决方案1】:

    这里有两个明显的问题:

    1. 选择器的语法错误; : 不标记参数部分的开始,它只是标记该函数完全接受参数。所以点击识别器应该初始化为UITapGestureRecognizer(target: self, action: "labelTicked:")。轻松修复。这是个好消息。

    2. 坏消息:即使语法完美,也无法按照您在此处设置的方式工作。您的点击识别器无法将 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 以将它们带到显示阅读作业详细信息的视图。是否有可能(如在精灵上)分割单元格,因此触摸单元格的前 1/4 会执行复选标记方法,而触摸单元格的其余部分会执行转场?
    【解决方案2】:

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

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

    但是当识别器触发时,您不能安排将任意对象传递给方法。更好的方法是创建UITableViewCell 的子类。我们称之为AssignmentCell。为子类赋予assignment 属性,并将labelTicked: 方法移至AssignmentCell

    如果您已在情节提要中设计了单元格,则可以将点击识别器添加到情节提要中的标签,并将识别器连接到情节提要中单元格的 labelTicked: 方法。

    在您的表格视图数据源的tableView(_:cellForRowAtIndexPath:) 中,将单元格出列后,将其assignment 属性设置为该行的赋值。

    【讨论】:

    • 感谢罗布的评论。我还在学习编程,所以我对你所说的有一个基本的了解(我认为)。那么,我可以让我的 WeeklyAssignment 类从 UITableViewCell 继承...你知道吗,我想我明白你在说什么,但不知道如何做你所描述的。
    猜你喜欢
    • 2017-09-01
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    相关资源
    最近更新 更多