【问题标题】:How to pass argument to a method without going through selector Swift?如何在不通过选择器 Swift 的情况下将参数传递给方法?
【发布时间】:2019-02-11 04:09:33
【问题描述】:

我在 Swift 中有一个应用程序,它在一个页面上有多个 UISegmentedControls,所有这些都有相同的目标,即方法“answerClicked”。但是,我需要一种方法将信息传递给此方法,说明刚刚单击了 WHICH UISegmentedControl。

我知道参数不能通过选择器传递——有没有一种方法可以获得这些信息并将其传递给“answerClicked”方法?

class Flowchart{
    //Init segmented controls up here...

    segmentedControl0.addTarget(self, action: #selector(answerClicked), for: .valueChanged)
    segmentedControl1.addTarget(self, action: #selector(answerClicked), for: .valueChanged)
    segmentedControl2.addTarget(self, action: #selector(answerClicked), for: .valueChanged)    

    @objc func answerClicked(){
        //Ideally would have an argument "segmentedControlNumber: Int"
        //How else to tell 0, 1, and 2 apart?
    }
}

【问题讨论】:

    标签: swift function methods


    【解决方案1】:

    Vacawama 的回答很好,非常适合您提出的问题,但我建议不要使用标签。它们很脆弱。您必须记住在情节提要中设置标签,如果您更改了内容,很容易忘记维护它们。

    相反,我建议使用 Vacawama 的答案中的发件人来确定哪个控件被点击:

    var controls: [UISegmentedControl]!
    
    override func viewDidLoad() {
      super.viewDidLoad()
      controls = [segmentedControl1, segmentedControl2, segmentedControl3]
    }
    
    @IBAction func answerClicked(_ sender: UISegmentedControl) {
        if let index = controls.index( { where sender === $0 } ) {
           //act on your index
        } else {
           //error case; could not find sender in controls array. (Should not happen)
        }
    }
    

    编辑:

    或者如果你想使用 switch 语句,你可以这样写:

    @IBAction func answerClicked(_ sender: UISegmentedControl) {
      switch sender {
         case segmentedControl1:
            //code for control 1
         case segmentedControl2:
            //code for control 2
         case segmentedControl3:
            //code for control 3
         default: 
            //error case
            //break
       }
    }
    

    【讨论】:

    • 如果 3 个分段控件实际上是 outlet,则使用 outlet 集合来获取控件数组。
    • @rmaddy,除了不保证出口集合中项目的顺序。顺序通常是它们添加到集合中的顺序,但有时不是。我以前也被这个咬过。
    • 有趣的地方。我从不使用故事板或插座,所以我没有考虑过这个可能的问题。
    • 奥特莱斯收藏的一个非常烦人的特性严重限制了它们的实用性。
    • controls 需要是属性而不是局部变量。 controls.index(where: { sender === $0 } )。您不必在情节提要中设置tag。在我的示例中,它们是在分配目标/操作的同时设置的。
    【解决方案2】:

    为每个UISegmentedControls 设置tag 属性,然后使用sender 作为值更改方法的第一个参数发送来获取tag

    class Flowchart {
        //Init segmented controls up here...
    
        func setup() {
            segmentedControl1.addTarget(self, action: #selector(answerClicked), for: .valueChanged)
            segmentedControl1.tag = 1
    
            segmentedControl2.addTarget(self, action: #selector(answerClicked), for: .valueChanged)
            segmentedControl2.tag = 2
    
            segmentedControl3.addTarget(self, action: #selector(answerClicked), for: .valueChanged)
            segmentedControl3.tag = 3  
        }  
    
        @objc func answerClicked(_ sender: UISegmentedControl) {
            switch sender.tag {
            case 1:
                // code to handle segmentedControl1
            case 2:
                // code to handle segmentedControl2
            case 3:
                // code to handle segmentedControl3
            default:
                break
            }
        }
    }
    

    注意:正如@rmaddy 在 cmets 中所说,最好避免使用标签0,因为默认情况下所有视图都会收到标签值0。我从 1 开始重命名了您的分段控件。

    【讨论】:

    • 谢谢!这完美地工作。你为我节省了大量时间和挫折。
    • 最好避免使用显式标签0,因为默认情况下所有视图都有0标签。
    猜你喜欢
    • 1970-01-01
    • 2011-04-22
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 2012-08-30
    相关资源
    最近更新 更多