简体   繁体   English

将参数传递给Swift中的Selector

[英]passing parameters to a Selector in Swift

I am building an app for keeping track of reading assignments for a university course. 我正在构建一个应用程序,用于跟踪大学课程的阅读作业。 Each ReadingAssignment has included a Bool value that indicates if the reader has finished reading the assignment. 每个ReadingAssignment都包含一个Bool值,表示读者是否已完成阅读作业。 The ReadingAssignments are collected into WeeklyAssignment arrays. ReadingAssignments被收集到WeeklyAssignment数组中。 I want to have the user be able to touch a label and have a checkmark appear and show the assignment as completed. 我希望用户能够触摸标签并显示复选标记,并将分配显示为已完成。 I would like this touch to also update the .checked property to true so I can persist the data. 我希望这个触摸也将.checked属性更新为true,这样我就可以保存数据。 So, I am trying to have the gestureRecognizer call the labelTicked() method. 所以,我试图让gestureRecognizer调用labelTicked()方法。 This works and prints to the console. 这适用于打印到控制台。 However, when I try to pass in the assignment parameter, it compiles, but crashes on the touch with an "unrecognized selector" error. 但是,当我尝试传入赋值参数时,它会编译,但在触摸时会因“无法识别的选择器”错误而崩溃。 I have read every topic i can find here, and haven't found the solution. 我已经阅读了我在这里可以找到的每个主题,并且没有找到解决方案。 They all say ":" signifies a Selector with parameters, but still no go. 他们都说“:”表示带参数的选择器,但仍然没有。 Can you see what I am doing wrong? 你能看出我做错了什么吗?

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 = ""
        }
}

I would also love to pass in the UILabel checkLabel so I can update it in the labelTicked() method. 我也想传递UILabel checkLabel,所以我可以在labelTicked()方法中更新它。 Thanks for your help. 谢谢你的帮助。

There are two distinct problems here: 这里有两个不同的问题:

  1. The syntax for the selector is wrong; 选择器的语法错误; the : doesn't mark the beginning of a parameters part, it merely marks that this function takes parameters at all. :不标记参数部分的开头,它只标记该函数完全采用参数。 So the tap recognizer should be initialized as UITapGestureRecognizer(target: self, action: "labelTicked:") . 因此,应将tap识别器初始化为UITapGestureRecognizer(target: self, action: "labelTicked:") Easy fix. 轻松修复。 That is the good news. 这是个好消息。

  2. The bad news: even with perfect syntax it will not work the way you set it up here. 坏消息:即使语法完美,它也不会像你在这里设置的那样工作。 Your tap recognizer cannot pass a WeeklyAssignment object as a parameter. 您的点击识别器无法将WeeklyAssignment对象作为参数传递。 In fact, it cannot pass any custom parameter at all. 实际上,它根本无法传递任何自定义参数。 At least, not like that. 至少,不是那样的。

What it can pass, however, is its sender (which is usually the view the gesture recognizer is attached to). 然而,它可以传递的是它的sender (通常是手势识别器所附着的视图)。 You can grab it by changing your method to 您可以通过将方法更改为来获取它

func labelTicked(sender: AnyObject) {

(note that AnyObject may be declared as a more specific type if you know exactly what to expect.) (请注意,如果您确切知道期望的内容, AnyObject可能会被声明为更具体的类型。)

Going through the sender, you could now theoretically infer which label it is that has been tapped, which data entity that labels corresponds to, and which state the checked property of that entity is in. I think this would become very convoluted very quickly. 通过发送者,您现在理论上可以推断出哪个标签被点击,标签对应哪个数据实体,以及该实体的已checked属性的状态。我认为这将非常快速地变得非常复杂。

Seemingly straightforward things becoming convoluted is usually a good sign that we should take a step back and look for a better solution. 看似简单易懂的事情通常是一个好兆头,我们应该退一步寻找更好的解决方案。

I'd suggest dropping the whole GestureRecognizer approach at this point, and instead exploit the fact that each cell in a table view already comes with its own "tap recongizing" functionality out of the box: the didSelectRowAtIndexPath: method of the table view's delegate. 我建议在这一点上放弃整个GestureRecognizer方法,而是利用表视图中的每个单元格已经开箱即用的“tap recongizing”功能这一事实didSelectRowAtIndexPath:表视图委托的didSelectRowAtIndexPath:方法。 There, you can easily use the supplied NSIndexPath to retrieve the corresponding model entity from the data source to read and modify its parameters as you see fit. 在那里,您可以轻松地使用提供的NSIndexPath从数据源中检索相应的模型实体,以根据需要读取和修改其参数。 Via cellForRowAtIndexPath: you can then get a reference to the correct cell and change its contents accordingly. 通过cellForRowAtIndexPath:然后您可以获得对正确单元格的引用并相应地更改其内容。


Update for Swift 3: Swift 3更新:

As the Swift language evolves and using String-based selectors (eg "labelTicked:" ) is now flagged as deprecated, I think it's appropriate to provide a small update to the answer. 随着Swift语言的发展和使用基于字符串的选择器(例如"labelTicked:" )现在被标记为已弃用,我认为提供答案的小更新是合适的。

Using more modern syntax, you could declare your function like this: 使用更现代的语法,您可以像这样声明您的函数:

@objc func labelTicked(withSender sender: AnyObject) {

and initialize your gesture recognizer like this, using #selector : 并使用#selector初始化你的手势识别#selector

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

The correct selector for that function is labelTicked: . 该函数的正确选择器是labelTicked: . Furthermore, you can use a string directly as a selector. 此外,您可以直接使用字符串作为选择器。 Thus: 从而:

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

But you can't arrange to pass an arbitrary object along to the method when the recognizer fires. 但是,当识别器触发时,您无法安排将任意对象传递给方法。 A better way to do this is to create a subclass of UITableViewCell . 更好的方法是创建UITableViewCell的子类。 Let's call it AssignmentCell . 我们称之为AssignmentCell Give the subclass an assignment property, and move the labelTicked: method to AssignmentCell . 为子类assignment属性,并将labelTicked:方法移动到AssignmentCell

If you've designed the cell in your storyboard, you can add a tap recognizer to the label right in the storyboard, and wire the recognizer to the cell's labelTicked: method in the storyboard. 如果您在故事板中设计了单元格,则可以在故事板中的标签处添加点击识别器,并将识别器连接到故事板中单元格的labelTicked:方法。

In your table view data source's tableView(_:cellForRowAtIndexPath:) , after you've dequeued the cell, set its assignment property to the assignment for that row. 在表视图数据源的tableView(_:cellForRowAtIndexPath:) ,在单元格出列后,将其assignment属性设置为该行的赋值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM