Cannot convert value of type 'ViewController' to expected argument type 'UIButton' in Swift 4

I'm trying to call a button function after loading it before viewDidLoad() like this:

@IBAction func tap(_ sender: UIButton) {
        if(Date().dayNumberOfWeek() == 4) {
            let alert = UIAlertController(title: "My Title", message: "This is my message.", preferredStyle: UIAlertControllerStyle.alert)
        }
    }

override func viewDidLoad() {
        super.viewDidLoad()

        tap(self)

This returns Cannot convert value of type 'ViewController' to expected argument type 'UIButton'

How do I fix this?

5 answers

  • answered 2018-01-13 17:08 Sh_Khan

    Edit:

    @IBAction func tap(_ sender: UIButton) {
        if(Date().dayNumberOfWeek() == 4) {
            let alert = UIAlertController(title: "My Title", message: "This is my message.", preferredStyle: UIAlertControllerStyle.alert)
    
             self.present(alert, animated: true)           
        }
    
    }
    

    Also , keep in mind that your code shows a UIAlertController in viewDidload which may not appear as view hierarchy is not yet loaded so better put the code in viewDidAppear like this

    override  func viewDidAppear()
    {
      tap(UIButton())
    }
    

    Also the condition Date().dayNumberOfWeek() == 4 must be satisfied to see the alert

  • answered 2018-01-13 17:11 Sam

    The tap method is expecting a UIButton. But, in the viewDidLoad method, you are calling the tap method with self which is a UIViewController. They are two separate classes.

    If you do not care about the class of the calling object, you can change the method declaration to

    @IBAction func tap(_ sender: Any)
    

  • answered 2018-01-13 17:40 rmaddy

    The error is pretty clear. You are passing a view controller to a method that is expecting a button.

    Presumably your tap action is connected to some UIButton in your user interface which is why the tap method is expecting a UIButton argument.

    Since it seems you wish to manually call this tap method from viewDidLoad, you should pass a reference to the button it is connected to.

    Assuming you have an IBOutlet for the UIButton, then pass that outlet to the call to tap.

    @IBOutlet var myButton: UIButton! // an example of your existing outlet
    

    Change your line in viewDidLoad to:

    tap(myButton)
    

    Replace myButton with the actual name of your outlet.

    Another option, since your tap method doesn't actually make use of the sender parameter, is to get rid of the parameter.

    @IBAction func tap() {
        // your existing code
    }
    

    Then in viewDidLoad you simply do:

    tap()
    

  • answered 2018-01-13 17:43 bscazz11

    The function is expecting a button type. If you have an IBOUtlet to the button you can pass that in instead.

    class Controller: UIViewController {
        @IBOutlet var button: UIButton!
    
        @IBAction func tap(_ sender: UIButton) {
            if(Date().dayNumberOfWeek() == 4) {
                let alert = UIAlertController(title: "My Title", message: "This is my message.", preferredStyle: UIAlertControllerStyle.alert)
            }
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tap(button)
        }
    

  • answered 2018-01-13 17:47 Grant Emerson

    Most people like to follow the convention of extracting the code for the IBAction out into a private function.

    @IBAction func tap(_ sender: UIButton) {
        presentAlertIfNecessary()
    }
    private func presentAlertIfNecessary() {
        if(Date().dayNumberOfWeek() == 4) {
            let alert = UIAlertController(title: "My Title", message: "This is my message.", preferredStyle: UIAlertControllerStyle.alert)
             self.present(alert, animated: true)           
        }
    }
    

    This way you can call the function in viewDidAppear.

    override func viewDidAppear() {
        presentAlertIfNecessary()
    }